home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 July: Mac OS SDK / Dev.CD Jul 99 SDK1.toast / Development Kits / Mac OS / QuickDraw3D 1.6 SDK / Mac SampleCode New for 1.6 / ViewerFrameWorkSample / VwrFrameWork.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-05-18  |  147.3 KB  |  5,360 lines  |  [TEXT/CWIE]

  1. /*
  2.  * This is a viewer application shell
  3.  *
  4.  * Nick Thompson, nickt@apple.com
  5.  * send bug reports to devsupport@apple.com
  6.  *
  7.  * ©1995-7 Apple Computer Inc., All Rights Reserved.
  8.  *
  9.  * This is a sample app that was originally written for an article in Develop
  10.  * issue 29, but please note that it is really extended from the example 
  11.  * presented in that article.  
  12.  *
  13.  * I've extended it to be the "reference" app for supporting plug-in 
  14.  * renderers.  Along the way it became apparent that just sticking all the renderers
  15.  * into a popup menu, simply did not cut the mustard.  Here's why.  There is a 
  16.  * distinction between interactive (for example the apple interactive renderer)
  17.  * and non interactive renderers (such as the lightwork renderer).  Bear in mind
  18.  * that the interactivity of a renderer is often a tradeoff against speed.  In particular, 
  19.  * it makes no sense whatsoever to support interactivity with a non interactive
  20.  * renderer.
  21.  *
  22.  * This led me to the big change in the application.  I decided that if the 
  23.  * renderer was non-interactive, then it should draw into a new window, which
  24.  * the user could save as a pict, print, or whatever.  Bear in mind that this is
  25.  * not the only way to do this.  Another simpler way would be to let the user
  26.  * chose a non interactive renderer, and just render one into the window, then
  27.  * switch back to the non interactive renderer.  I saw a couple of problems with
  28.  * this approach for this particular application, in particular that if the 
  29.  * window received an update event (out of the users control) then the window 
  30.  * or worse - part of the window - would get redrawn with the "wrong" renderer.
  31.  *
  32.  * This remains a work in progress.  As sample code it is useful as an 
  33.  * illustration of how to use the viewer, and an illustration of how to use
  34.  * plug-in renderers.
  35.  *
  36.  * As usual this is a work in progress, which means use the code at your own risk!!  
  37.  *
  38.  * If you fix a bug, or add some functionality feel free to send me the change and
  39.  * I'll roll it in.
  40.  *
  41.  * 
  42.  *
  43.  * TO DO: drag and drop support for pict windows
  44.  *        saving and restoring print records to files.
  45.  *
  46.  * 2/4/99 nick updated to universal headers 3.2 and CW4.
  47.  */
  48.  
  49.  
  50. /*------------------------------------------------------------ */
  51.  
  52. #include <AppleEvents.h>
  53. #include <CodeFragments.h>
  54. #include <ColorPicker.h>
  55. #include <Devices.h>
  56. #include <Dialogs.h>
  57. #include <Diskinit.h>
  58. #include <Events.h>
  59. #include <Errors.h>
  60. #include <Fonts.h>
  61. #include <Gestalt.h>
  62. #include <LowMem.h>
  63. #include <Printing.h>
  64. #include <QDOffscreen.h>
  65. #include <QuickDraw.h>
  66. #include <Menus.h>
  67. #include <Scrap.h>
  68. #include <SegLoad.h>
  69. #include <StandardFile.h>
  70. #include <TextUtils.h>
  71. #include <Strings.h>
  72. #include <Sound.h>
  73. #include <Windows.h>
  74.  
  75. // is alpha macros etc...
  76. #include <ctype.h>
  77.  
  78. /* always include this before anything else when using the QuickDraw 3D library  */
  79. #include "QD3D.h"
  80.  
  81. /* viewer support  */
  82. #include "QD3DViewer.h"
  83.  
  84. /* this has the routines for renderer objects  */
  85. #include "QD3DRenderer.h"
  86.  
  87. /* this has the routines for view objects  */
  88. #include "QD3DView.h"
  89.  
  90.  
  91. /*------------------------------------------------------------ */
  92.  
  93. /* convenience macros to peek at event records  */
  94.  
  95. #define     HiWrd(aLong)            (((aLong) >> 16) & 0xFFFF)
  96. #define     LoWrd(aLong)            ((aLong) & 0xFFFF)
  97.  
  98. #define     kMaxRendererCount        30
  99. #define        RETURN_KEY                 0x0D
  100. #define        ENTER_KEY                 0x03
  101. #define        ESCAPE                     0x1B
  102.  
  103. #define        kProgressBarDlogID        1028
  104. #define        kProgressBarPBItemID    2
  105.  
  106.  
  107. /*------------------------------------------------------------ */
  108.  
  109. /* constants  */
  110. const    short                kWindHeight = 350 ;            /* default theWindow height  */
  111. const    short                kWindWidth = 300 ;            /* default theWindow width  */
  112. const    short                kMaxHeight = 400 ;            /* max theWindow height  */
  113. const    short                kMaxWidth = 560 ;            /* max theWindow width  */
  114. const    SFTypeList            kTypeList = { '3DMF' } ;    /* file type we can open  */
  115. const    short                kNumTypes = 1 ;             /* num of file types we can recognise  */
  116.  
  117. const    short                kAppMenuBarID = 128 ;        /* resource ID for the application's menu bar  */
  118. const    short                kFatalAlert = 128 ;            /* res ID for error alert before we bail  */
  119. const    short                 kErrorAlertStrings = 128 ;    /* res ID for alert strs  */
  120. const    short                kAboutDialogID = 129;        /* ID for the about box dialog  */
  121. const    short                kFinalRenderDialogID = 130;    /* ID for the final quality render dialog  */
  122.  
  123. const    short                kInsetPixelsConst = 30 ;    /* num of pixels to inset view by  */
  124. /* error codes  */
  125. enum {
  126.     kNoMenuBar = 1,
  127.     kNoQD3DViewerLib,
  128.     kNoAEVTSupport
  129. } ;
  130.  
  131. /* menu resource IDs  */
  132. enum {
  133.     mInteractiveRendererMenu = 1,    /* hierarchical, stored in the view menu  */
  134.     mNonInteractiveRendererMenu ,    /* hierarchical, stored in final dialog  */
  135.     mAppleMenu = 128,
  136.     mFileMenu,
  137.     mEditMenu,
  138.     mViewMenu
  139. } ;
  140.  
  141. /* item numbers - Apple menu  */
  142. enum {
  143.     iAppleAboutItem = 1
  144. } ;
  145.  
  146. /* item numbers - File menu  */
  147. enum {
  148.     iFileNewItem = 1,
  149.     iFileOpenItem,
  150.     iFileCloseItem = 4,
  151.     iFileSaveItem,
  152.     iFileSaveAsItem,
  153.     iFileRevertItem,
  154.     iFilePageSetupItem = 9,
  155.     iFilePrintItem,
  156.     iFileQuitItem = 12
  157. } ;
  158.  
  159. /* item numbers - Edit menu  */
  160. enum {
  161.     iEditUndoItem = 1,
  162.     iEditCutItem = 3,
  163.     iEditCopyItem,
  164.     iEditPasteItem,
  165.     iEditClearItem = 7,
  166.     iEditRendererPrefsItem = 9
  167. } ;
  168.  
  169. /* item numbers - View menu  */
  170. enum {
  171.     iViewRendererItem = 1,
  172.     iViewFinalRendererItem,
  173.     iViewBadgeItem = 4,
  174.     iViewCameraButtonItem = 6,
  175.     iViewTruckButtonItem,
  176.     iViewOrbitButtonItem,
  177.     iViewZoomButtonItem,
  178.     iViewDollyButtonItem,
  179.     iViewInsetNFrameItem = 12,
  180.     iViewSetBackgroundColorItem
  181. } ;
  182.  
  183. /* items in the final quality render menu */
  184. enum {
  185.     kFinalRendrOK = 1,
  186.     kFinalRendrCancel,
  187.     kFinalRendrIcon,
  188.     kFinalRendrTitle,
  189.     kFinalRendrText,
  190.     kFinalRendrSep1,
  191.     kFinalRendrSep2,
  192.     kFinalRendrSep3,
  193.     kFinalRendrPopup,
  194.     kFinalRendrConfigure,
  195.     kFinalRendrWinSzTxt,
  196.     kFinalRendrHtTxt,
  197.     kFinalRendrWiTxt,
  198.     kFinalRendrHeight,
  199.     kFinalRendrWidth
  200. } ;
  201.  
  202.  
  203. /* res ID's for small picts used in the progress bar dialog */
  204. enum {
  205.     kResIDStartCap = 1028,
  206.     kResIDEndCap,
  207.     kResIDDropShadow
  208. } ;
  209.  
  210.  
  211. /*------------------------------------------------------------ */
  212.  
  213. /*
  214.  * type definitions - these magic numbers are the first field of the struct
  215.  * that we stuff in the window's refcon field
  216.  */
  217.  
  218. /*
  219.  * as this app grow's I'm in the process of factoring it, here's a list
  220.  * of functions that can be stuffed in the document record 
  221.  */
  222. typedef    void         (*AdjustMenusProc)( WindowPtr  theWindow )    ;
  223. typedef Boolean     (*HandleEventProc)( WindowPtr theWindow, const EventRecord *theEventRecord) ;
  224. typedef    void         (*UpdateContentProc)( WindowPtr  theWindow ) ;
  225. typedef WindowPtr     (*NewProc)( unsigned char *windowTitle ) ;
  226. typedef OSErr         (*SaveAsProc)( WindowPtr theWindow ) ;
  227. typedef OSErr         (*SaveProc)( WindowPtr theWindow ) ;
  228. typedef OSErr         (*RevertProc)( WindowPtr theWindow ) ;
  229. typedef WindowPtr     (*OpenProc)( FSSpec *theFSSpec ) ;
  230. typedef OSErr         (*CloseProc)( WindowPtr theWindow ) ;
  231. typedef short        (*CountPagesProc)( WindowPtr theWindow, Rect *pageRect ) ;
  232. typedef void        (*PrintPageProc)( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  233. typedef    void         (*PrePrintProc)( WindowPtr  theWindow )    ;
  234. typedef    void         (*PostPrintProc)( WindowPtr  theWindow )    ;
  235. typedef    OSErr        (*CutProc)( WindowPtr    theWindow ) ;
  236. typedef    OSErr        (*CopyProc)( WindowPtr    theWindow ) ;
  237. typedef    OSErr        (*PasteProc)( WindowPtr    theWindow ) ;
  238. typedef    OSErr        (*ClearProc)( WindowPtr    theWindow ) ;
  239. typedef    OSErr        (*UndoProc)( WindowPtr    theWindow ) ;
  240.  
  241. /*
  242.  * This struct is used to store related items for a progress bar,
  243.  * these cached items can then be used when updating the PB
  244.  */
  245. typedef struct {
  246.     DialogPtr        thePBDialog ;        /* the dialog containing a 14 pixel high user item  *
  247.                                          * within which the PB is drawn                     */
  248.     short            thePBItemNumber ;    /* item number in the DITL for the PB user item */
  249.     Rect            thePBRect ;            /* it's rect, local coodinates in the dialog */
  250.     
  251.     GWorldPtr        thePBGWorld ;        /* a GWorld that is used to draw the pb, it's then blitted to the dialog */
  252.     
  253.     long            thePBMaxValue ;        /* the maximum value the PB can be */
  254.     long            thePBCurrValue ;    /* the current value for the progress bar */
  255.     
  256. } ProgressBarDlogInfoData, **ProgressBarDlogInfoHdl ;
  257.  
  258.  
  259.  
  260. /*
  261.  * this is a struct that contains the fp's associated with a document class
  262.  * later we'll use this to set up menus.  If a fp is null then the menu is 
  263.  * disabled, this will really reduce the size of the adjust menus proc.
  264.  *
  265.  * Each document record will have this as the second field.
  266.  */
  267.  
  268. typedef struct Procs {
  269.     AdjustMenusProc        adjustMenusP ;        /* fix up window specific menus */
  270.     UpdateContentProc    updateWindowP ;        /* redraw the window */
  271.     HandleEventProc        handleEventP ;        /* handle events for the window */
  272.     NewProc                newP ;                /* do window specific stuff post create (unused at the moment) */
  273.     SaveAsProc            saveAsP ;            /* save the window contens ask for a file */
  274.     SaveProc            saveP ;                /* save the window contents to the original file */
  275.     RevertProc            revertP ;            /* revert to the last saved copy of the windows file */
  276.     OpenProc            openP ;                /* read in some document data */
  277.     CloseProc            closeP ;            /* close and destroy */
  278.     CountPagesProc        countPagesP ;        /* count the number of pages for a print job */
  279.     PrintPageProc        printPageP ;        /* print one page */
  280.     PrePrintProc        prePrintP ;            /* stuff to do before printing */
  281.     PostPrintProc        postPrintP ;        /* stuff to do after printing */
  282.     CutProc                cutProc ;            /* handle clipboard cut, same as copy followed by clear */
  283.     CopyProc            copyProc ;            /* handle clipboard copy */
  284.     PasteProc            pasteProc ;            /* paste compatible scrap type from the scrap */
  285.     ClearProc            clearProc ;            /* clear the document contents without a save to the scrap */
  286.     UndoProc            undoProc ;            /* undo the last action - if supported */
  287. } Procs ;
  288.  
  289.  
  290. /*
  291.  * eventually to make a new doc, we'll just define the structure of the private 
  292.  * field for each class.  Right now they are kind of copies which can be cast around.
  293.  *
  294.  * Make sure that the fields are in the same order, again this is something I'm 
  295.  * planning to fix.
  296.  */
  297. typedef struct {
  298.     unsigned long        fDocumentMagic ;    /* use this to describe the contents of the fPrivate field */
  299.     Procs                *procs ;            /* a pointer to a set of function pointers for this window type */
  300.     THPrint                fPrintRec ;            /* print record so we can print the doc contents */
  301.     void                *fPrivate ;            /* the private data associated with this class */
  302.     
  303. } Document, *DocumentPtr, **DocumentHdl ;
  304.  
  305. /* these structures get stuffed in the private field of a generic document record */
  306. typedef struct {
  307.     TQ3ViewerObject        fViewer ;        /* stores reference to the viewer object  */
  308.     GWorldPtr            fGWorld ;        /* used temporarily during printing */
  309.     FSSpec                fFSSpec    ;        /* reference to the file for the document  */
  310. } ViewerData, *ViewerDataPtr, **ViewerDataHdl ;
  311.  
  312.  
  313. typedef struct {
  314.     GWorldPtr            fGWorld ;        /* a buffer that stores the picture */
  315. } PictData, *PictDataPtr, **PictDataHdl ;
  316.  
  317.  
  318. /*
  319.  * Structure for the private data for a popup control.
  320.  * This structure is documented on page 5-77 
  321.  * Inside Macintosh: Macintosh Toolbox Essentials
  322. */
  323. typedef struct popupPrivateData {
  324.     MenuHandle     mHandle;      /* the popup menu handle */
  325.     short         mID;         /* the popup menu ID */
  326.     /*
  327.      * after these two public fields is the mPrivate private data, 
  328.      * which may be any old size and should not be messed with 
  329.      */
  330. }    popupPrivateData;
  331.  
  332. /*------------------------------------------------------------ */
  333.  
  334. /* function prototypes for the application  */
  335.  
  336. void             SetUpRendererMenu( void ) ;
  337. void             TearDownRendererMenu( void ) ;
  338.  
  339. void            LoadApplicationDialogs( void ) ;
  340. void            LoadMenuBarForApplication( short myMenuBarID ) ;
  341. void             FatalAlert( short theErrorMessage ) ;
  342. void            InitializeToolBox( void ) ;
  343. Boolean         HasQuickDraw3DViewer( void ) ;
  344. Boolean         SupportsAEVT( void ) ;
  345. void             RegisterRequiredAppleEventHandlers( void ) ;
  346.  
  347. /* routines to handle the renderer progress bar */
  348. ProgressBarDlogInfoHdl PB_New( 
  349.                 DialogPtr     thePBDialog,
  350.                 short         thePBItemNumber,
  351.                 long        maxValue,
  352.                 long        currValue ) ;
  353.  
  354. void            PB_Update(ProgressBarDlogInfoHdl theInfo ) ;
  355. void            PB_Delete(ProgressBarDlogInfoHdl theInfo ) ;
  356.  
  357. pascal OSErr     HandleCoreAppleEventOfTypeOAPP(    AppleEvent *theAppleEvent, 
  358.                                 AppleEvent *theAppleEventReply, 
  359.                                 long userDefinedReferenceConstant) ;
  360.                                 
  361. pascal OSErr     HandleCoreAppleEventOfTypeODOC( AppleEvent *theAppleEvent, 
  362.                                 AppleEvent *theAppleEventReply, 
  363.                                 long userDefinedReferenceConstant) ;
  364.                                 
  365. pascal OSErr     HandleCoreAppleEventOfTypePDOC( AppleEvent *theAppleEvent, 
  366.                                 AppleEvent *theAppleEventReply,
  367.                                 long userDefinedReferenceConstant) ;
  368.                                 
  369. pascal OSErr     HandleCoreAppleEventOfTypeQUIT( AppleEvent *theAppleEvent, 
  370.                                 AppleEvent *theAppleEventReply,
  371.                                 long userDefinedReferenceConstant) ; 
  372.                                 
  373. void            MainEventLoop( void ) ; 
  374. TQ3Boolean         HandleEvent( const EventRecord *theEventRecord ) ;
  375.  
  376. void             HandleKeyPress(const EventRecord *theEventRecord) ;
  377. void             HandleMenuCommand(long menuResult) ;
  378. void             HandleAppleMenu( short menuItem ) ;
  379. void             HandleFileMenu( short menuItem ) ;
  380. OSErr             HandleFilePageSetupItem( WindowPtr theWindow ) ;
  381. OSErr             HandleFilePrintItem( WindowPtr theWindow ) ;
  382. OSErr             HandleFileQuitItem( void ) ;
  383. void             HandleEditMenu( short menuItem ) ;
  384. pascal Boolean     OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit) ;
  385. void             HandleViewFinalRendererOption( void ) ;
  386. void             HandleInteractiveRendererMenu( short menuItem ) ;
  387. void             HandleViewMenu( short menuItem ) ;
  388. OSErr             GetViewerVersion( unsigned long *major, unsigned long *minor ) ;
  389.  
  390. Boolean         BackgroundColor(RGBColor *theRGBColor, unsigned char *thePrompt ) ;
  391. void             AdjustMenus( void ) ;
  392. void            DoDrawGrowIcon(WindowPtr theWindow) ;
  393.  
  394. WindowPtr         DoCreateNewViewerWindow( unsigned char *windowName ) ;
  395.  
  396. void            ViewerWindow_Update( WindowPtr  theWindow ) ;
  397. void             ViewerWindow_AdjustMenus( WindowPtr  theWindow ) ;
  398. Boolean            ViewerWindow_HandleEvent( WindowPtr theWindow, const EventRecord *theEventRecord) ;
  399. WindowPtr         ViewerWindow_New( unsigned char *windowTitle ) ;
  400. OSErr             ViewerWindow_SaveAs( WindowPtr theWindow ) ;
  401. OSErr             ViewerWindow_Save( WindowPtr theWindow ) ;
  402. OSErr             ViewerWindow_Revert( WindowPtr theWindow ) ;
  403. WindowPtr         ViewerWindow_Open( FSSpec *theFSSpec ) ;
  404. OSErr             ViewerWindow_Close( WindowPtr theWindow ) ;
  405. short            ViewerWindow_CountPages( WindowPtr theWindow, Rect *pageRect ) ;
  406. void            ViewerWindow_PrintPage( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  407. void             ViewerWindow_PrePrint( WindowPtr theWindow ) ;
  408. void             ViewerWindow_PostPrint( WindowPtr theWindow ) ;
  409. OSErr            ViewerWindow_Cut( WindowPtr    theWindow ) ;
  410. OSErr            ViewerWindow_Copy( WindowPtr    theWindow ) ;
  411. OSErr            ViewerWindow_Paste( WindowPtr    theWindow ) ;
  412. OSErr            ViewerWindow_Clear( WindowPtr    theWindow ) ;
  413. OSErr            ViewerWindow_Undo( WindowPtr    theWindow ) ;
  414.  
  415. WindowPtr         DoCreateNewPictWindow( unsigned char *windowName, long windWidth, long windHeight ) ;
  416. void            PictWindow_Update( WindowPtr  theWindow ) ;
  417. void             PictWindow_AdjustMenus( WindowPtr  theWindow ) ;
  418. Boolean            PictWindow_HandleEvent( WindowPtr theWindow, const EventRecord *theEventRecord) ;
  419. WindowPtr         PictWindow_New( unsigned char *windowTitle ) ;
  420. OSErr             PictWindow_SaveAs( WindowPtr theWindow ) ;
  421. OSErr             PictWindow_Save( WindowPtr theWindow ) ;
  422. OSErr             PictWindow_Revert( WindowPtr theWindow ) ;
  423. WindowPtr         PictWindow_Open( FSSpec *theFSSpec ) ;
  424. OSErr             PictWindow_Close( WindowPtr theWindow ) ;
  425. short            PictWindow_CountPages( WindowPtr theWindow, Rect *pageRect ) ;
  426. void            PictWindow_PrintPage( WindowPtr theWindow, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  427. void             PictWindow_PrePrint( WindowPtr theWindow ) ;
  428. void             PictWindow_PostPrint( WindowPtr theWindow ) ;
  429. OSErr             PictWindow_Copy( WindowPtr theWindow ) ;
  430.  
  431. //
  432.  
  433. OSErr SetupPrintHdl(THPrint *hPrint) ;
  434. void DoCreatePrintRecord( DocumentHdl theDocument ) ;
  435. OSErr DoStyleDlog(THPrint hPrint) ;
  436. OSErr DoJobDlog(THPrint hPrint) ;
  437. OSErr CommandPeriod() ;
  438. pascal void IdleProc() ;
  439. short GeneralCountPages( GWorldPtr theGWorld, Rect *pageRect ) ;
  440. void GeneralPrintPage( GWorldPtr theGWorld, Rect *pageRect, GrafPtr imagingPort, short pageNum ) ;
  441. OSErr DoPrintLoop( WindowPtr theWindow ) ;
  442.  
  443.  
  444.  
  445. TQ3ViewerObject    GetViewerFromViewerWindow( WindowPtr theWindow ) ;
  446. GWorldPtr GetGWorldFromPictWindow( WindowPtr  theWindow ) ;
  447. TQ3RendererObject    GetRendererByType(TQ3ObjectType theRendererType) ;
  448. TQ3Status    ViewerSetRenderer( TQ3ObjectType theRendererType, TQ3ViewerObject theViewer ) ;
  449. TQ3Status MyViewIdleProgressMethod( 
  450.     TQ3ViewObject        view,
  451.     const void            *idlerData,        /* contains the dialog ref */
  452.     unsigned long        current,
  453.     unsigned long        completed) ;
  454. OSErr GetOutputPictFileRef(short    *dstPictFRef ) ;
  455.  
  456.  
  457. /*------------------------------------------------------------ */
  458.  
  459. /* global variables  */
  460. DialogPtr            gFinalRenderDialog = NULL ;    /* the non interactive renderer dial0g */
  461. DialogPtr            gProgressModelessDialog = NULL ;
  462.  
  463. Boolean                gQuitFlag = false ;    /* set to true to quit application  */
  464. AEAddressDesc        gSelfAddress;        /* A self-addressed address descriptor record  */
  465.  
  466. /* these are used for the menus */
  467. static TQ3ObjectType        pInteractiveTypes[ kMaxRendererCount ] ; /* renderer types installed - includes plug-ins */
  468. static TQ3ObjectType        pNonInteractiveTypes[ kMaxRendererCount ] ; /* renderer types installed - includes plug-ins */
  469. static long                    pNonInteractiveRendererCount = 0;    /* the number of non-interactive renderers installed on this system */
  470. static long                    pInteractiveRendererCount = 0;        /* the number of interactive renderers installed on this system */
  471. static Boolean                pHasFinalQualityRenderer = false ;    /* set true if one or more non interactive renderers are installed */
  472.  
  473. /* 
  474.  * this is a list of the installed renderers that we can use to switch easily. 
  475.  * By this point you are probably muttering that this app has way to many globals,
  476.  * and you might be right, however keeping a list of renderer objects makes sense.
  477.  * The most obvious reason to build a list of the available renderers, together
  478.  * with an instance of each mish be efficiency considerations, but the real reason
  479.  * is somewhat more subtle.  We want renderer prefs to be "sticky".  In other words
  480.  * if I set prefs for a renderer I want those prefs to be the same for multiple
  481.  * uses of the renderer.  Just setting the renderer is not enough, since each time 
  482.  * a renderer object is created it is created with the default set of prefs which
  483.  * may not be what I selected last time I bought the prefs dialog up.
  484.  *
  485.  * The way this structure is used is to build a list of renderer types and an 
  486.  * instance of each when the application is launched, then this list is used
  487.  * whenever renderer prefs need to be set or when a new renderer is selected.
  488.  * This way the prefs will stay with the renderer for the life time of the program.
  489.  *
  490.  * This list contains both interactive and non interactive renderers, it has no
  491.  * real order (first come first served) and is seached linearly by renderer type.
  492.  *
  493.  * In the future, it might be good to build a list of renderer prefs for each 
  494.  * document and save these along with the document, or to have a global list of
  495.  * prefs for the application..
  496.  */
  497.  
  498. static struct {
  499.     TQ3ObjectType         fRendererType ;        /* the object type for this renderer */
  500.     TQ3RendererObject    fRendererObject ;    /* an instance of the renderer type */    
  501. } pRendererList[ 2 * kMaxRendererCount ] ;
  502.  
  503. static short         pRendererCount = 0 ;        /* indexes the pRendererList array */
  504.  
  505. ModalFilterUPP        gModalFilterProcUPP ; 
  506.  
  507. /********************************************************************************
  508.  * Colors used to draw the progress bar 
  509.  */
  510.  
  511. /* 
  512.  
  513. I got these by dumping a scroll bar from the MacOS 8 finder and poking around in photoshop.
  514.  
  515. Color table, byte value (e.g. from photoshop) on LHS
  516.  
  517. 8bit    16bit        16bit (Hex)
  518.  
  519. 0,         0,             0x0000
  520. 51,     13107,         0x3333
  521. 102,     26214,         0x6666
  522. 136,     34952,         0x8888
  523. 153,     39321,        0x9999
  524. 170,     43690,        0xaaaa
  525. 187,     48059,        0xbbbb
  526. 204,     52428,        0xcccc
  527. 221,     56797,        0xdddd
  528. 255,     65535,        0xffff
  529.  
  530. */
  531.  
  532. const RGBColor        RGBBlack    = { 0x0000, 0x0000, 0x0000 } ;
  533. const RGBColor        RGBDkGrey    = { 0x8888, 0x8888, 0x8888 } ;
  534. const RGBColor        RGBMedGrey    = { 0xaaaa, 0xaaaa, 0xaaaa } ;
  535. const RGBColor        RGBGrey        = { 0xbbbb, 0xbbbb, 0xbbbb } ;
  536. const RGBColor        RGBLtGrey    = { 0xdddd, 0xdddd, 0xdddd } ;
  537. const RGBColor        RGBWhite    = { 0xffff, 0xffff, 0xffff } ;
  538.  
  539. /* blue shades used */
  540. const RGBColor        RGBDkBlue    = { 0x3333, 0x3333, 0x6666 } ;
  541. const RGBColor        RGBMedBlue    = { 0x6666, 0x6666, 0x9999 } ;
  542. const RGBColor        RGBBlue        = { 0x9999, 0x9999, 0xcccc } ;
  543. const RGBColor        RGBLtBlue    = { 0xcccc, 0xcccc, 0xffff } ;
  544.  
  545.  
  546. static    GWorldPtr    theStartCap     = NULL;
  547. static    GWorldPtr    theEndCap         = NULL ;
  548. static    GWorldPtr    theDropShadow     = NULL ;
  549.  
  550. const unsigned long kViewerMagic    =    0xBADB00CA ;    /* viewer windows */
  551. const unsigned long kPICTMagic        =    0xBADABADA ;    /* picture windows */
  552.  
  553. /* these MUST be in the same order as above or bad things happen.
  554.  * function procs for the regular viewer window.  Setting these up
  555.  * this way is a little dangerous, if the fields get jumbled up
  556.  * unexpected results can happen, it might make more sense to use
  557.  * a metahandler approach to install the methods - like QD3D
  558.  * extensions...
  559.  */
  560. Procs viewerProcs = { 
  561.     ViewerWindow_AdjustMenus, 
  562.     ViewerWindow_Update, 
  563.     ViewerWindow_HandleEvent,
  564.     ViewerWindow_New, 
  565.     ViewerWindow_SaveAs, 
  566.     ViewerWindow_Save, 
  567.     ViewerWindow_Revert, 
  568.     ViewerWindow_Open, 
  569.     ViewerWindow_Close,
  570.     ViewerWindow_CountPages,
  571.     ViewerWindow_PrintPage,
  572.     ViewerWindow_PrePrint,
  573.     ViewerWindow_PostPrint,
  574.     ViewerWindow_Cut,
  575.     ViewerWindow_Copy,
  576.     ViewerWindow_Paste,
  577.     ViewerWindow_Clear,
  578.     ViewerWindow_Undo
  579.     
  580. };
  581.  
  582. /* function procs for the pict window */
  583. Procs pictProcs = { 
  584.     PictWindow_AdjustMenus, 
  585.     PictWindow_Update, 
  586.     PictWindow_HandleEvent,
  587.     PictWindow_New, 
  588.     PictWindow_SaveAs, 
  589.     PictWindow_Save, 
  590.     PictWindow_Revert, 
  591.     PictWindow_Open, 
  592.     PictWindow_Close,
  593.     PictWindow_CountPages,
  594.     PictWindow_PrintPage,
  595.     NULL,                        /* pre print method is not supported */
  596.     NULL,                        /* post print method is not supported */
  597.     NULL,                        /* cut method is not supported */
  598.     PictWindow_Copy,
  599.     NULL,                        /* paste method is not supported */
  600.     NULL,                        /* clear method is not supported */
  601.     NULL                        /* undo method is not supported */
  602. };
  603.  
  604. /*------------------------------------------------------------ */
  605.  
  606.  
  607. /* REMOVE THIS */
  608.  
  609. #include <Types.h>
  610. #include <Memory.h>
  611. #include <Quickdraw.h>
  612. #include <Gestalt.h>
  613. #include <Fonts.h>
  614. #include <Events.h>
  615. #include <Menus.h>
  616. #include <Windows.h>
  617. #include <TextEdit.h>
  618. #include <Dialogs.h>
  619. #include <OSUtils.h>
  620. #include <ToolUtils.h>
  621. #include <SegLoad.h>
  622. #include <Notification.h>
  623. #include <OSUtils.h>
  624.  
  625.     
  626. /* Prototypes */
  627. Boolean IsVMCurrentlyOn(void) ;
  628. void notify(void) ;
  629.  
  630. static Str255        VMIsCurrentlyOnStr        = "\pVirtual memory is currently on" ;
  631. static Str255        VMIsCurrentlyOffStr        = "\pVirtual memory is currently off" ;
  632.  
  633. static    NMRec        myNotification ;
  634. void notify(void)
  635. {
  636.     OSErr theErr ;
  637.  
  638.     myNotification.qType = nmType ;
  639.     myNotification.nmIcon = NULL ;
  640.     myNotification.nmSound = NULL ;
  641.     myNotification.nmResp = NULL ;
  642.     myNotification.nmRefCon = 0L ;
  643.     
  644.     /* check Gestalt to see if VM is on */
  645.     if( IsVMCurrentlyOn() )
  646.     {
  647.         myNotification.nmStr = VMIsCurrentlyOnStr ;
  648.     
  649.     }
  650.     else
  651.     {
  652.         myNotification.nmStr = VMIsCurrentlyOffStr ;
  653.     
  654.     }
  655.     
  656.     theErr = NMInstall( &myNotification ) ;
  657.     
  658. }
  659.  
  660. /*
  661.  * returns true if the VM is on
  662.  */
  663. Boolean IsVMCurrentlyOn(void)
  664. {
  665.     OSErr theError;
  666.     long response;
  667.         
  668.     theError = Gestalt(gestaltVMAttr, &response);
  669.     if (theError!=noErr)
  670.         return false;
  671.         
  672.     return (response && (response << gestaltVMPresent));
  673. }
  674.  
  675.  
  676. /* END REMOVE THIS */
  677.  
  678. void main(void)
  679. {
  680.     InitializeToolBox() ;
  681.     gModalFilterProcUPP = NewModalFilterProc( OurFilter ) ;
  682.     LoadApplicationDialogs() ;
  683.     LoadMenuBarForApplication( kAppMenuBarID ) ;
  684.  
  685.     /*
  686.      * check that we have AppleEvents, and if so install the
  687.      * AppleEvent handlers for the required AppleEvents
  688.      */
  689.     
  690.     if( SupportsAEVT() ) 
  691.     {
  692.         RegisterRequiredAppleEventHandlers() ;
  693.         
  694.         /*
  695.          * Check that the viewer is installed
  696.          */
  697.         if( HasQuickDraw3DViewer() )
  698.         {
  699.             Q3Initialize() ;
  700.             SetUpRendererMenu() ;
  701.  
  702.             MainEventLoop() ;
  703.             
  704.             TearDownRendererMenu() ;
  705.             Q3Exit() ;
  706.         }
  707.     }
  708.  
  709.     ExitToShell();    
  710.     
  711. }
  712.  
  713. /*------------------------------------------------------------ */
  714.  
  715. /*
  716.  * Load the final quality renderer dialog.  We do this here so
  717.  * that we can set up the menu properly.  Don't display it just 
  718.  * yet though.
  719.  */
  720. void    LoadApplicationDialogs(void)
  721. {
  722.     /* 
  723.      * load the dialog but don't show it.  As a side note since the 
  724.      * dialog is going to be around for a while, the items in the dialog 
  725.      * should not be purgable.
  726.      */
  727.     gFinalRenderDialog = GetNewDialog( kFinalRenderDialogID, NULL, (WindowPtr)-1) ;
  728.     gProgressModelessDialog = GetNewDialog( kProgressBarDlogID, nil, (WindowPtr)-1) ;
  729.     
  730.     /* the popup menu for the renderers is item 9 */
  731. }
  732.  
  733. /*------------------------------------------------------------ */
  734.  
  735. /*
  736.  * Load the menu bar specified.
  737.  */
  738.  
  739. void LoadMenuBarForApplication( short myMenuBarID )
  740. {
  741.     Handle        menuBar = NULL;
  742.  
  743.     /* 
  744.      *Read menus into menu bar specified by the resource 
  745.      * id passed into this routine by myMenuBarID 
  746.      */
  747.     menuBar = GetNewMBar(myMenuBarID);    
  748.     
  749.     if ( menuBar == NULL )
  750.          ExitToShell();
  751.          
  752.     /* Install the menus we just read in  */              
  753.     SetMenuBar(menuBar);
  754.     
  755.     /* it is now safe to dispose the menu handle  */
  756.     DisposeHandle(menuBar);
  757.     
  758.     /* 
  759.      * this next routine adds the names of desk accessories 
  760.      * to the specified menu, in this case the apple menu
  761.      */
  762.     AppendResMenu( GetMenuHandle( mAppleMenu ), 'DRVR' );
  763.     
  764.     /*
  765.      * now add the two hierarchical menus
  766.      */
  767.     InsertMenu(GetMenu( mInteractiveRendererMenu ), -1);
  768.     
  769.     /* call our routine to grey out menus as appropriate  */
  770.     AdjustMenus() ;
  771.     
  772.     /* finally ensure the new menubar gets drawn  */
  773.     DrawMenuBar();
  774. }
  775. /*------------------------------------------------------------ */
  776.  
  777. /*
  778.  * dispose of the global rtenderer list
  779.  */
  780. void TearDownRendererMenu( void )
  781. {
  782.     long        theIndex ;
  783.     
  784.     for( theIndex = 0; theIndex < pRendererCount ; theIndex++ ) 
  785.         Q3Object_Dispose( pRendererList[ theIndex ].fRendererObject ) ;
  786. }
  787.  
  788.  
  789. /*------------------------------------------------------------ */
  790.  
  791. /*
  792.  * set up the interactive renderer menu and the non interactive 
  793.  * renderer popup menu for the "final render" dialog.  Build up
  794.  * a list of renderer objects in the pRendererList struct to make 
  795.  * switching between renderers easier
  796.  */
  797.  
  798. void SetUpRendererMenu( void ) 
  799. {
  800.     MenuHandle                    theMenu, interactiveRendererMenu, nonInteractiveRendererMenu ;
  801.     TQ3SubClassData                subClassData;
  802.     TQ3ObjectType                *classPointer;
  803.     short                        i;
  804.     TQ3ObjectClassNameString    objectClassName;
  805.     TQ3RendererObject            tempRendererObject ;
  806.     unsigned char                nameBuffer[256] ;
  807.     unsigned long                actualLength ;
  808.     TQ3ObjectClassNameString     objectClassString ;
  809.     Boolean                        isInteractive ;
  810.     popupPrivateData            **myPopupPrivateDataPtr ;
  811.     
  812.     /* some variables for accessing the fields of the dialog */
  813.     short                iKind;
  814.     Handle                iHandle;
  815.     Rect                iRect;
  816.         
  817.     interactiveRendererMenu = GetMenuHandle(mInteractiveRendererMenu);
  818.  
  819.     /*
  820.      * Set up the dialog renderer popup.  We know the item number for the popup
  821.      * we need to get the menuhandle associated with the control, it is in the private
  822.      * control data field, as documented in Inside Macintosh: Toolbox page 5-77
  823.      */
  824.     
  825.     /* get the control handle for the popup    from the dialog */    
  826.     GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  827.     
  828.     /* extract from the control the menuhandle */
  829.     myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  830.     nonInteractiveRendererMenu = (**myPopupPrivateDataPtr).mHandle ;
  831.     HLock((Handle)nonInteractiveRendererMenu) ;
  832.     
  833.     /* the popup control has a problem under 7.5 and 7.6, since it expects the 
  834.      * menu to alredy be constructed otherwise the default value for the control 
  835.      * is 0, which means nothing is selected after the menu items have been added, 
  836.      * so i put a dummy item in the menu, we need to delete this before adding 
  837.      * any new items
  838.      */
  839.      
  840.     DeleteMenuItem ( nonInteractiveRendererMenu, 1 ) ;
  841.     Q3ObjectHierarchy_GetSubClassData(kQ3SharedTypeRenderer, &subClassData);
  842.     
  843.     classPointer = subClassData.classTypes;
  844.     
  845.     i = subClassData.numClasses;
  846.     
  847.     while( i-- > 0 && pInteractiveRendererCount <= kMaxRendererCount) {
  848.         
  849.         /* 
  850.          * the "generic" renderer is used internally, it can't draw, 
  851.          * so don't display it in any user interface item
  852.          */
  853.         if( *classPointer != kQ3RendererTypeGeneric )
  854.         {
  855.             /*
  856.              * Q3RendererClass_GetNickNameString is only available on 1.5.1, so 
  857.              * check for the existance of this trap before calling.  If the call 
  858.              * is not installed just set the string to nil, we'll use the class name
  859.              * instead and everthing will be hunky dory.
  860.              */
  861.             if( Q3RendererClass_GetNickNameString != (void *)kUnresolvedCFragSymbolAddress ) 
  862.                 Q3RendererClass_GetNickNameString(*classPointer, objectClassString );
  863.             else
  864.                 objectClassString[0] = '\0' ;
  865.                 
  866.             /*
  867.              * Create an instance of a renderer object and then call 
  868.              * Q3Renderer_IsInteractive to determine if the renderer is 
  869.              * an interactive renderer (this is something the renderer 
  870.              * tells QuickDraw 3D).  Stash the renderer and the type in
  871.              * the pRendererList structure array.
  872.              */
  873.              
  874.             tempRendererObject = Q3Renderer_NewFromType( *classPointer ) ;
  875.             isInteractive = Q3Renderer_IsInteractive( tempRendererObject ) ;
  876.             
  877.             /* cache the renderer and type */
  878.             pRendererList[ pRendererCount ].fRendererType = *classPointer ;
  879.             pRendererList[ pRendererCount ].fRendererObject = tempRendererObject;
  880.             pRendererCount++ ;        /* bump the count of elements in the array */
  881.             
  882.             if( isInteractive )
  883.             {
  884.                 theMenu = interactiveRendererMenu ;
  885.                 pInteractiveTypes[pInteractiveRendererCount++] = *classPointer ;
  886.             }
  887.             else
  888.             {
  889.                 theMenu = nonInteractiveRendererMenu ;
  890.                 pHasFinalQualityRenderer = true ;
  891.                 pNonInteractiveTypes[pNonInteractiveRendererCount++] = *classPointer ;
  892.             }
  893.             /*
  894.              * check to see if we got a string back, if not use the renderer class name
  895.              */
  896.                 
  897.             if( objectClassString[0] == '\0' )
  898.             {
  899.                 /* the renderer did not provide the name, just use the class name */
  900.                 Q3ObjectHierarchy_GetStringFromType(*classPointer, objectClassName);
  901.                 
  902.                 AppendMenu(theMenu,c2pstr((char *)objectClassName));
  903.             }
  904.             else
  905.             {
  906.                 AppendMenu(theMenu,c2pstr(objectClassString));
  907.             }
  908.                 
  909.         }
  910.         
  911.         classPointer++ ;        
  912.     }
  913.     
  914.     HLock((Handle)nonInteractiveRendererMenu) ;
  915.     
  916.     /* null terminate the arrays */
  917.     pInteractiveTypes[pInteractiveRendererCount] = NULL ;
  918.     pNonInteractiveTypes[pInteractiveRendererCount] = NULL ;
  919.     pRendererList[ pRendererCount ].fRendererType = 0L ;
  920.     pRendererList[ pRendererCount ].fRendererObject = NULL;
  921.     
  922.     Q3ObjectHierarchy_EmptySubClassData( &subClassData ) ;
  923. }
  924.  
  925. /*------------------------------------------------------------ */
  926.  
  927. /*
  928.  * Display an alert and quit.
  929.  */
  930.  
  931. void FatalAlert( short theErrorMessage )
  932. {
  933.     unsigned char    *thePString, theErrorStr[256] ;
  934.     
  935.     thePString = theErrorStr ;
  936.     
  937.     GetIndString( thePString, kErrorAlertStrings, theErrorMessage ) ;
  938.     ParamText( thePString, "\p", "\p", "\p" ) ;
  939.     StopAlert( kFatalAlert, NULL ) ;
  940.     ExitToShell() ;
  941. }
  942.  
  943. /*------------------------------------------------------------ */
  944.  
  945. /*
  946.  * Initialize all the needed managers.
  947.  */
  948.  
  949. void     InitializeToolBox( void )
  950. {
  951.     /*
  952.      * Initialize the toolbox managers
  953.      */
  954.     InitGraf((Ptr)&qd.thePort);
  955.     InitFonts();
  956.     InitWindows();
  957.     InitMenus();
  958.     TEInit();
  959.     InitDialogs((long)NULL);
  960.     InitCursor();
  961.  
  962.     /*
  963.      * must call this so that the heap is expanded to maximum
  964.      * size before calling any viewer routines
  965.      */
  966.     MaxApplZone() ;
  967.     
  968. }
  969.  
  970. /*------------------------------------------------------------ */
  971.  
  972. /*
  973.  * return true if the viewer is installed
  974.  */
  975.  
  976. Boolean     HasQuickDraw3DViewer( void )
  977. {
  978.     return((long) Q3ViewerNew != kUnresolvedCFragSymbolAddress) ;
  979. }
  980.  
  981. /*------------------------------------------------------------ */
  982.  
  983. /*
  984.  * returns true if the platform supports appleevents - we won't run
  985.  * if it doesn't
  986.  */
  987. Boolean SupportsAEVT(void)
  988. {
  989.     OSErr theError;
  990.     long response;
  991.         
  992.     theError = Gestalt(gestaltAppleEventsAttr,&response);
  993.     if (theError!=noErr)
  994.         return false;
  995.         
  996.     return (response && (response << gestaltAppleEventsPresent));
  997. }
  998.  
  999.  
  1000. /********************************************************************************
  1001.  * LoadPictIntoGWorld - read pict from the current resource chain, create a 32 bit
  1002.  * GWorld the size of the pict, image the pict into the GWorld, dispose of the 
  1003.  * pict.  Return a reference to the gworld.
  1004.  */
  1005.  
  1006. static GWorldPtr LoadPictIntoGWorld( short resID )
  1007. {
  1008.     Rect        pictRect ;
  1009.     GWorldPtr    theGWorld = NULL;
  1010.     QDErr        theErr ;
  1011.     PicHandle    aPicH = GetPicture(resID);
  1012.     
  1013.     if( aPicH != NULL ) 
  1014.     {
  1015.         /* create a GWorld the size of the pict */
  1016.         pictRect.top = (**aPicH).picFrame.top ;
  1017.         pictRect.left = (**aPicH).picFrame.left ;
  1018.         pictRect.bottom = (**aPicH).picFrame.bottom ;
  1019.         pictRect.right = (**aPicH).picFrame.right ;
  1020.         OffsetRect(&pictRect, -pictRect.left, -pictRect.top);
  1021.         
  1022.         theErr = NewGWorld(&theGWorld, 32, &pictRect, NULL, NULL, 0L) ;
  1023.         if( theErr != noErr )
  1024.             theGWorld = NULL ;
  1025.         else
  1026.         {
  1027.             CGrafPtr        savedPort ;
  1028.             GDHandle        gdh ;
  1029.             
  1030.             GetGWorld( &savedPort, &gdh);
  1031.             SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  1032.             
  1033.             DrawPicture( aPicH, &theGWorld->portRect ) ;
  1034.             
  1035.             SetGWorld( savedPort, gdh);
  1036.         }
  1037.     }
  1038.     
  1039.     return theGWorld ;
  1040. }
  1041.  
  1042.  
  1043. /*------------------------------------------------------------ */
  1044.  
  1045. /*
  1046.  * PBNew set up for a new progress bar in a dialog, get all of the info we'll
  1047.  * need in order to draw it and allocate a GWorld to composite the Scroll bar.
  1048.  */
  1049.  
  1050. ProgressBarDlogInfoHdl    PB_New( 
  1051.     DialogPtr     thePBDialog, 
  1052.     short         thePBItemNumber,
  1053.     long        maxValue,
  1054.     long        currValue )
  1055. {
  1056.     ProgressBarDlogInfoHdl    theInfo ;
  1057.     
  1058.     /* first make sure we have the requisite pict's loaded */
  1059.     if(theStartCap == NULL )
  1060.         theStartCap = LoadPictIntoGWorld( kResIDStartCap ) ;
  1061.         
  1062.     if(theEndCap == NULL )
  1063.         theEndCap = LoadPictIntoGWorld( kResIDEndCap ) ;
  1064.         
  1065.     if(theDropShadow == NULL )
  1066.         theDropShadow = LoadPictIntoGWorld( kResIDDropShadow ) ;
  1067.             
  1068.     theInfo = (ProgressBarDlogInfoHdl)NewHandle(sizeof(ProgressBarDlogInfoData)) ;
  1069.     if( theInfo != NULL ) 
  1070.     {
  1071.         short        itemType ;
  1072.         Handle        item ;
  1073.         Rect        box ;
  1074.         QDErr        theErr ;
  1075.         GWorldPtr    theOffscreen ;
  1076.         
  1077.         /* stash the other values passed in */
  1078.         (**theInfo).thePBDialog = thePBDialog ;            /* reference to the dialog containing the progressbar */
  1079.         (**theInfo).thePBItemNumber = thePBItemNumber ;    /* the item number in the dialog that is the progress bar */
  1080.         (**theInfo).thePBMaxValue = maxValue ;            /* the max value that the progress bar can be */
  1081.         (**theInfo).thePBCurrValue = currValue ;        /* current value of the progress bar (usually 0 ) */
  1082.         
  1083.         /* get the rect of the given item number in local co-ordinates */
  1084.         GetDialogItem(thePBDialog, thePBItemNumber, &itemType, &item, &box) ;
  1085.                 
  1086.         /* save the box information, we'll use this to draw into */
  1087.         (**theInfo).thePBRect.top         = box.top ;
  1088.         (**theInfo).thePBRect.left         = box.left ;
  1089.         (**theInfo).thePBRect.bottom     = box.bottom ;
  1090.         (**theInfo).thePBRect.right     = box.right ;
  1091.         
  1092.         OffsetRect( &box, -box.left, -box.top ) ;
  1093.     
  1094.         /* make a new GWorld for the progress bar, we composite the PB in here and copy to the screen */
  1095.         theErr = NewGWorld( &theOffscreen, 32, &box, NULL, NULL, 0L);
  1096.         if( theErr != noErr || theOffscreen == NULL )
  1097.         {
  1098.             /* we couldn't create the offscree, zero the info rec. */
  1099.             DisposeHandle((Handle)theInfo) ;
  1100.             theInfo = NULL ;
  1101.         }
  1102.         else
  1103.         {
  1104.             (**theInfo).thePBGWorld = theOffscreen ;
  1105.         }
  1106.     }
  1107.     return theInfo ;
  1108. }
  1109.  
  1110. /*------------------------------------------------------------ */
  1111.  
  1112. /*
  1113.  * Redraw the progress bar, assumes the caller has just updated the 
  1114.  * value in current.
  1115.  */
  1116. void    PB_Update( ProgressBarDlogInfoHdl theInfo )
  1117. {
  1118.     CGrafPtr    savedPort ;
  1119.     GDHandle    gdh ;
  1120.     Rect        theFrame ;
  1121.     short        numPixels ;
  1122.     Rect        tmpRect ;
  1123.     
  1124.     Rect        destRect ;
  1125.     
  1126.     HLock((Handle)theInfo) ;
  1127.     
  1128.     GetGWorld( &savedPort, &gdh);
  1129.     SetGWorld( (CGrafPtr)(**theInfo).thePBGWorld, NULL ) ;
  1130.         
  1131.     /* fill the entire rect with the default grey */
  1132.     
  1133.     RGBForeColor(&RGBGrey) ;
  1134.     PaintRect(&(**theInfo).thePBGWorld->portRect) ;
  1135.     
  1136.     /* frame the outline of the progress bar */
  1137.     
  1138.     /* copy the rect to the frame rect */
  1139.     theFrame.top     = (**theInfo).thePBGWorld->portRect.top ;
  1140.     theFrame.left     = (**theInfo).thePBGWorld->portRect.left ;
  1141.     theFrame.bottom    = (**theInfo).thePBGWorld->portRect.bottom ;
  1142.     theFrame.right     = (**theInfo).thePBGWorld->portRect.right ;
  1143.     
  1144.     /* how long is the progress part of the progress bar in pixels */
  1145.     numPixels = ((float)(**theInfo).thePBCurrValue / (**theInfo).thePBMaxValue ) 
  1146.                     * ((**theInfo).thePBGWorld->portRect.right - (**theInfo).thePBGWorld->portRect.left - 2) ;
  1147.     
  1148.     /* and inset for the frame */
  1149.     InsetRect( &theFrame, 1, 1 ) ;
  1150.  
  1151.     RGBForeColor( &RGBBlack ) ;
  1152.     FrameRect( &theFrame ) ;
  1153.     
  1154.     /* apply highlight to top and left edges (outermost) */
  1155.     MoveTo( (**theInfo).thePBGWorld->portRect.left, 
  1156.             (**theInfo).thePBGWorld->portRect.bottom - 1) ;
  1157.  
  1158.     RGBForeColor( &RGBLtGrey ) ;
  1159.     MoveTo( (**theInfo).thePBGWorld->portRect.left, 
  1160.             (**theInfo).thePBGWorld->portRect.bottom - 2 ) ;
  1161.  
  1162.     
  1163.     RGBForeColor( &RGBMedGrey ) ;
  1164.     LineTo( (**theInfo).thePBGWorld->portRect.left, 
  1165.             (**theInfo).thePBGWorld->portRect.top );        
  1166.             
  1167.     LineTo( (**theInfo).thePBGWorld->portRect.right - 1, 
  1168.             (**theInfo).thePBGWorld->portRect.top );
  1169.             
  1170.     /* hit the pixel at the top left */        
  1171.     RGBForeColor( &RGBLtGrey ) ;
  1172.     LineTo( (**theInfo).thePBGWorld->portRect.right, 
  1173.             (**theInfo).thePBGWorld->portRect.top );
  1174.     
  1175.     /* right and bottom edges */
  1176.     RGBForeColor( &RGBWhite ) ;
  1177.     MoveTo( (**theInfo).thePBGWorld->portRect.right - 1, 
  1178.             (**theInfo).thePBGWorld->portRect.top + 1 ) ;
  1179.             
  1180.     LineTo( (**theInfo).thePBGWorld->portRect.right - 1, 
  1181.             (**theInfo).thePBGWorld->portRect.bottom - 1);
  1182.     
  1183.     LineTo( (**theInfo).thePBGWorld->portRect.left + 1, 
  1184.             (**theInfo).thePBGWorld->portRect.bottom - 1);
  1185.     
  1186.     
  1187.     /* apply highlight to top and left edges (innermost) */
  1188.     MoveTo( (**theInfo).thePBGWorld->portRect.left + 2, 
  1189.             (**theInfo).thePBGWorld->portRect.bottom - 3) ;
  1190.     
  1191.     RGBForeColor( &RGBDkGrey ) ;
  1192.     
  1193.     LineTo( (**theInfo).thePBGWorld->portRect.left + 2, 
  1194.             (**theInfo).thePBGWorld->portRect.top + 2 ) ;        
  1195.             
  1196.     LineTo( (**theInfo).thePBGWorld->portRect.right - 4, 
  1197.             (**theInfo).thePBGWorld->portRect.top + 2) ;
  1198.     
  1199.     /* hit the single pixel in the inside corner */
  1200.     RGBForeColor( &RGBGrey ) ;
  1201.     
  1202.     LineTo( (**theInfo).thePBGWorld->portRect.right - 3, 
  1203.             (**theInfo).thePBGWorld->portRect.top + 2) ;
  1204.     
  1205.  
  1206.     /* right and bottom */
  1207.     RGBForeColor( &RGBLtGrey ) ;
  1208.     
  1209.     LineTo( (**theInfo).thePBGWorld->portRect.right - 3, 
  1210.             (**theInfo).thePBGWorld->portRect.bottom - 3) ;
  1211.             
  1212.     LineTo( (**theInfo).thePBGWorld->portRect.left + 3, 
  1213.             (**theInfo).thePBGWorld->portRect.bottom - 3) ;
  1214.             
  1215.     RGBForeColor( &RGBBlack ) ;
  1216.     
  1217.     /* set up the rect for the progress part of the PB */
  1218.     tmpRect.top = theFrame.top ;
  1219.     tmpRect.left = theFrame.left  ;
  1220.     tmpRect.bottom = theFrame.bottom ;
  1221.     tmpRect.right = theFrame.right ;
  1222.     
  1223.     InsetRect( & tmpRect, 1, 1 ) ;
  1224.     tmpRect.right = theFrame.left + numPixels ;
  1225.  
  1226.     /* lock the compositing GWorld for updates */
  1227.     LockPixels(GetGWorldPixMap((**theInfo).thePBGWorld)) ;
  1228.  
  1229.     /* what do we want to draw today */
  1230.     if( numPixels <= 8 )
  1231.     {
  1232.         /* we don't start doing the 3d effect until we have enough pixels for the
  1233.          * start and end caps, so before that just draw a blue rect.
  1234.          */
  1235.         RGBForeColor( &RGBBlue ) ;
  1236.         PaintRect(&tmpRect) ;
  1237.         RGBForeColor( &RGBBlack ) ;
  1238.     }    
  1239.     else
  1240.     {
  1241.         short startLine = tmpRect.top ;
  1242.         
  1243.         /* draw the line gradation */
  1244.         MoveTo( tmpRect.left, startLine ) ;
  1245.         RGBForeColor( &RGBDkBlue ) ;
  1246.         LineTo( tmpRect.right, startLine++) ;
  1247.         
  1248.         MoveTo( tmpRect.left, startLine ) ;
  1249.         RGBForeColor( &RGBMedBlue ) ;
  1250.         LineTo( tmpRect.right, startLine++) ;
  1251.         
  1252.         MoveTo( tmpRect.left, startLine ) ;
  1253.         RGBForeColor( &RGBBlue ) ;
  1254.         LineTo( tmpRect.right, startLine++) ;
  1255.         
  1256.         MoveTo( tmpRect.left, startLine ) ;
  1257.         RGBForeColor( &RGBLtBlue ) ;
  1258.         LineTo( tmpRect.right, startLine++) ;
  1259.         
  1260.         MoveTo( tmpRect.left, startLine ) ;
  1261.         RGBForeColor( &RGBWhite ) ;
  1262.         LineTo( tmpRect.right, startLine++) ;
  1263.         
  1264.         MoveTo( tmpRect.left, startLine ) ;
  1265.         RGBForeColor( &RGBLtBlue ) ;
  1266.         LineTo( tmpRect.right, startLine++) ;
  1267.         
  1268.         MoveTo( tmpRect.left, startLine ) ;
  1269.         RGBForeColor( &RGBBlue ) ;
  1270.         LineTo( tmpRect.right, startLine++) ;
  1271.         
  1272.         MoveTo( tmpRect.left, startLine ) ;
  1273.         RGBForeColor( &RGBMedBlue ) ;
  1274.         LineTo( tmpRect.right, startLine++) ;
  1275.         
  1276.         MoveTo( tmpRect.left, startLine ) ;
  1277.         RGBForeColor( &RGBDkBlue ) ;
  1278.         LineTo( tmpRect.right, startLine++) ;
  1279.         
  1280.         MoveTo( tmpRect.left, startLine ) ;
  1281.         RGBForeColor( &RGBBlack ) ;
  1282.         LineTo( tmpRect.right, startLine++) ;
  1283.         
  1284.         if( theStartCap != NULL )
  1285.         {
  1286.             destRect.top = theStartCap->portRect.top ;
  1287.             destRect.left = theStartCap->portRect.left ;
  1288.             destRect.bottom = theStartCap->portRect.bottom ;
  1289.             destRect.right = theStartCap->portRect.right ;
  1290.             
  1291.             OffsetRect(&destRect, 2, 2) ;
  1292.             
  1293.             LockPixels(GetGWorldPixMap(theStartCap)) ;        
  1294.             CopyBits(    (BitMapPtr) &theStartCap->portPixMap, 
  1295.                         (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, 
  1296.                         & theStartCap->portRect, 
  1297.                         & destRect, 
  1298.                         srcCopy, 
  1299.                         0L ) ;
  1300.             UnlockPixels(GetGWorldPixMap(theStartCap)) ;        
  1301.         }
  1302.         
  1303.         if( theEndCap != NULL )
  1304.         {
  1305.             destRect.top = theEndCap->portRect.top ;
  1306.             destRect.left = theEndCap->portRect.left ;
  1307.             destRect.bottom = theEndCap->portRect.bottom ;
  1308.             destRect.right = theEndCap->portRect.right ;
  1309.             
  1310.             OffsetRect(&destRect, numPixels + 2 - 6 , 2) ;
  1311.             
  1312.             LockPixels(GetGWorldPixMap(theEndCap)) ;        
  1313.             CopyBits(    (BitMapPtr) &theEndCap->portPixMap, 
  1314.                         (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, 
  1315.                         & theEndCap->portRect, 
  1316.                         & destRect, 
  1317.                         srcCopy, 
  1318.                         0L ) ;
  1319.             UnlockPixels(GetGWorldPixMap(theEndCap)) ;        
  1320.         }
  1321.     }    
  1322.             
  1323.     
  1324.     /* handle the drop shadow */
  1325.     if( numPixels > 3 && theDropShadow != NULL )
  1326.     {
  1327.         destRect.top = theDropShadow->portRect.top ;
  1328.         destRect.left = theDropShadow->portRect.left ;
  1329.         destRect.bottom = theDropShadow->portRect.bottom ;
  1330.         destRect.right = theDropShadow->portRect.right ;
  1331.         
  1332.         OffsetRect(&destRect, numPixels + 2 - 3, 2) ;
  1333.         
  1334.         LockPixels(GetGWorldPixMap(theDropShadow)) ;        
  1335.         CopyBits(    (BitMapPtr) &theDropShadow->portPixMap, 
  1336.                     (BitMapPtr) &((**theInfo).thePBGWorld->portPixMap), 
  1337.                     & theDropShadow->portRect, 
  1338.                     & destRect, 
  1339.                     srcCopy, 
  1340.                     0L ) ;
  1341.         UnlockPixels(GetGWorldPixMap(theDropShadow)) ;        
  1342.     }
  1343.     
  1344.     
  1345.     SetGWorld( savedPort, gdh ) ;
  1346.         
  1347.     CopyBits(    (BitMapPtr) &(**theInfo).thePBGWorld->portPixMap, 
  1348.                 &(**theInfo).thePBDialog->portBits, 
  1349.                 &(**theInfo).thePBGWorld->portRect, 
  1350.                 &(**theInfo).thePBRect, 
  1351.                 srcCopy, 
  1352.                 0L ) ;
  1353.         
  1354.     UnlockPixels(GetGWorldPixMap((**theInfo).thePBGWorld)) ;
  1355.     
  1356.     HUnlock((Handle)theInfo) ;
  1357. }
  1358.  
  1359.  
  1360. /*------------------------------------------------------------ */
  1361.  
  1362. /*
  1363.  * free up a progress bar info record
  1364.  */
  1365. void    PB_Delete( ProgressBarDlogInfoHdl theInfo ) 
  1366. {
  1367.     GWorldPtr    theGWorld ;
  1368.     
  1369.     /* dispose of the GWorld associated with the info record */
  1370.     if((theGWorld = (**theInfo).thePBGWorld ) != NULL )
  1371.         DisposeGWorld( theGWorld ) ;
  1372.     
  1373.     
  1374.     /* 
  1375.      * dispose of the memory allocated for the picts used to 
  1376.      * build the progress bar first make sure we have the 
  1377.      * requisite pict's loaded 
  1378.      */
  1379.     if(theStartCap == NULL )
  1380.         DisposeGWorld( theStartCap ) ;
  1381.         
  1382.     if(theEndCap == NULL )
  1383.         DisposeGWorld( theEndCap ) ;
  1384.         
  1385.     if(theDropShadow == NULL )
  1386.         DisposeGWorld( theDropShadow ) ;
  1387.         
  1388.     /* last of all blow away the info record */
  1389.     DisposeHandle((Handle)theInfo) ;
  1390. }
  1391.  
  1392.  
  1393.  
  1394. /* printing support */
  1395.  
  1396.  
  1397.  
  1398. /*---------------------------------------------------------------------*/
  1399.  
  1400. /*
  1401.  * SetupPrintHdl - This routine returns a default print handle for the 
  1402.  * current printer driver.
  1403.  *
  1404.  * The printer driver is expected to be closed upon entry, and is 
  1405.  * therefore opened and closed in this routine.
  1406.  */
  1407.  
  1408. OSErr SetupPrintHdl(THPrint *hPrint)
  1409. {
  1410.     OSErr err;
  1411.     
  1412.     /*
  1413.      * Create a handle, open the printer driver, set the
  1414.      * default values for the handle, and close the driver.
  1415.      * Be on the lookout for errors.
  1416.      */
  1417.  
  1418.     *hPrint = (THPrint) NewHandle(sizeof(TPrint));
  1419.  
  1420.     if ( *hPrint != nil )
  1421.     {
  1422.         PrOpen() ;
  1423.  
  1424.         err = PrError() ;
  1425.                 
  1426.         if (err == noErr) 
  1427.         {
  1428.             PrintDefault( *hPrint ) ;
  1429.             err = PrError() ;
  1430.         }
  1431.  
  1432.         PrClose() ;
  1433.  
  1434.     }
  1435.     else
  1436.         err = MemError() ;
  1437.     
  1438.     return err;
  1439. }
  1440.  
  1441. void DoCreatePrintRecord( DocumentHdl theDocument )
  1442. {
  1443.     Boolean            changed = false ;
  1444.     char            theState = 0 ;
  1445.     short            theResRef ;
  1446.     FSSpec             theFile ;
  1447.     
  1448.     /*  create a new print record */
  1449.     theState = HGetState( (Handle)theDocument ) ;
  1450.     MoveHHi( (Handle)theDocument ) ;
  1451.     HLock( (Handle)theDocument ) ;
  1452.     
  1453.     if(SetupPrintHdl( &(**theDocument).fPrintRec ) == noErr) 
  1454.     {        
  1455.         /*  check we have a "good" print record */
  1456.         changed = PrValidate( (**theDocument).fPrintRec ) ;
  1457.         
  1458.     }
  1459.     HSetState( (Handle)theDocument, theState ) ;
  1460. }
  1461.  
  1462. /* ---------------------------------------------------------------------------------- */
  1463.  
  1464. OSErr DoStyleDlog(THPrint hPrint)
  1465. {
  1466.     OSErr    err = noErr ;
  1467.     Boolean    changed = false ;
  1468.     
  1469.     PrOpen() ;
  1470.     if((err = PrError()) == noErr ) {
  1471.         changed = PrStlDialog(hPrint);
  1472.         err = PrError();
  1473.         if (!err && !changed) err = iPrAbort;
  1474.     }
  1475.  
  1476.     PrClose();
  1477.     
  1478.     return err;
  1479. }
  1480.  
  1481. /* ---------------------------------------------------------------------------------- */
  1482.  
  1483. OSErr DoJobDlog(THPrint hPrint)
  1484. {
  1485.     OSErr    err = noErr ;
  1486.     Boolean    changed = false ;
  1487.     
  1488.     PrOpen() ;
  1489.     if((err = PrError()) == noErr ) {
  1490.         changed = PrJobDialog(hPrint);
  1491.         err = PrError();
  1492.         if (!err && !changed) err = iPrAbort;
  1493.     }
  1494.  
  1495.     PrClose();
  1496.     
  1497.     return err;
  1498. }
  1499.  
  1500. /* ---------------------------------------------------------------------------------- */
  1501. /*   CommandPeriod - This routine checks to see if the user has */
  1502. /*   pressed command-period.  The Printing Manager does this */
  1503. /*   for us, but a routine like this is helpful to allow users */
  1504. /*   to cancel in the middle of a rendering routine, rather */
  1505. /*   than only Printing Manager operations. */
  1506. /*    */
  1507. /*   If there's a command-period in the event queue, the */
  1508. /*   routine returns iPrAbort just like the Printing Manager. */
  1509. /*   Otherwise, it returns noErr. */
  1510.  
  1511. OSErr CommandPeriod()
  1512. {
  1513.     Boolean        cancel = false;
  1514.     EventRecord    evtRec;
  1515.     
  1516.     while (!cancel && (WaitNextEvent(keyDownMask | autoKeyMask, &evtRec, 0, nil)))
  1517.         cancel = (evtRec.modifiers & cmdKey) &&
  1518.                  ((evtRec.message & charCodeMask) == '.');
  1519.  
  1520.     return ((cancel)? iPrAbort: noErr);
  1521. }
  1522.  
  1523. /* ---------------------------------------------------------------------------------- */
  1524. /*  IdleProc - This routine is a PrIdleProcPtr that spins our */
  1525. /*   cursor and looks for command-period presses during */
  1526. /*   printing. */
  1527.  
  1528.  
  1529. pascal void IdleProc()
  1530. {
  1531.     OSErr        err;
  1532. //    BumpCursor();
  1533.     if (err = CommandPeriod()) 
  1534.         PrSetError(err);
  1535. }
  1536. /* ---------------------------------------------------------------------------------- */
  1537. short    GeneralCountPages( 
  1538.     GWorldPtr    theGWorld, 
  1539.     Rect         *pageRect ) 
  1540. {
  1541.     Rect            pictRect ;
  1542.     short            horizOffset, 
  1543.                     vertOffset,
  1544.                     pagesWide = 0,     /*  the number of pages wide the image is */
  1545.                     pagesHigh = 0,     /*  the number pages high for this image */
  1546.                     pageWidth,         /*  the width of one page */
  1547.                     pageHeight ;    /*  the height of one page */
  1548.  
  1549.     DocumentHdl        theDocumentHdl ;
  1550.     PictDataHdl        thePictDataHdl ;
  1551.     OSErr            theErr ;
  1552.  
  1553.     pictRect = theGWorld->portRect ;
  1554.     
  1555.     horizOffset = -(pictRect.left) ;
  1556.     vertOffset = -(pictRect.top) ;
  1557.     
  1558.     OffsetRect( &pictRect, horizOffset, vertOffset ) ;    /*  this should make the origin of the rect (0,0) */
  1559.  
  1560.     pageWidth = pageRect->right - pageRect->left ;
  1561.     pageHeight = pageRect->bottom - pageRect->top ;
  1562.     
  1563.     pagesWide = (1.0 + pictRect.right / pageWidth ) ;    /*  round up the number of pages to the nearest */
  1564.     pagesHigh = (1.0 + pictRect.top  / pageHeight ) ;    /*  whole page in each direction. */
  1565.  
  1566.     return pagesWide * pagesHigh ;
  1567. }
  1568.  
  1569. /* ---------------------------------------------------------------------------------- */
  1570.  
  1571. void    GeneralPrintPage( 
  1572.     GWorldPtr         theGWorld, 
  1573.     Rect             *pageRect, 
  1574.     GrafPtr         imagingPort, 
  1575.     short             pageNum ) 
  1576. {
  1577.     GWorldPtr        docGWorld;
  1578.     Rect            pictRect, rectToPrint,srcRect,dstRect;
  1579.     short            pagesWide,         /*  the number of pages wide the image is */
  1580.                     pagesHigh,         /*  the number pages high for this image */
  1581.                     horozTile,         /*  used in the loop to denote the H tile to print from the image */
  1582.                     vertTile ;         /*  used in the loop to denote the V tile to print from the image */
  1583.     short            thisPage = 1;    /*  used to find the page they want us to print */
  1584.     short            pictHOff,
  1585.                     pictVOff,
  1586.                     pictWidth,         /*  the width of the doc's GWorld */
  1587.                     pictHeight ;    /*  the height of the doc's GWorld */
  1588.     short            pageWidth,         /*  the width of one page */
  1589.                     pageHeight ;    /*  the height of one page */
  1590.     DocumentHdl        theDocumentHdl ;
  1591.     PictDataHdl        thePictDataHdl ;
  1592.     OSErr            theErr ;
  1593.     PixMapHandle    offPixMap ;
  1594.  
  1595.     pictRect = theGWorld->portRect ;
  1596.     
  1597.     SetPort( imagingPort ) ;
  1598.     
  1599.     pictHOff   = -(pictRect.left) ;
  1600.     pictVOff   = -(pictRect.top) ;
  1601.     pictWidth  = pictRect.right - pictRect.left ;
  1602.     pictHeight = pictRect.bottom - pictRect.top ;
  1603.     
  1604.     pageWidth = pageRect->right - pageRect->left ;
  1605.     pageHeight = pageRect->bottom - pageRect->top ;
  1606.     
  1607.     pagesWide = (1.0 + pictWidth  / pageWidth  ) ;    /*  round up the number of pages to the nearest */
  1608.     pagesHigh = (1.0 + pictHeight / pageHeight ) ;    /*  whole page in each direction. */
  1609.     
  1610.     thisPage = 1;
  1611.     for (vertTile=0; vertTile<pagesHigh; vertTile++)
  1612.     {
  1613.         for (horozTile=0; horozTile<pagesWide; horozTile++)
  1614.         {
  1615.         
  1616.             /*  check this is the page we were called to print */
  1617.             
  1618.             if( thisPage == pageNum )
  1619.             {
  1620.                 srcRect = *pageRect;
  1621.                 
  1622.                 OffsetRect( &srcRect,
  1623.                             pictRect.left - srcRect.left,
  1624.                             pictRect.top  - srcRect.top );
  1625.                     
  1626.                 OffsetRect( &srcRect,
  1627.                             horozTile * pageWidth,
  1628.                             vertTile * pageHeight );
  1629.                 
  1630.                 SectRect( &srcRect, &pictRect, &srcRect);
  1631.                 
  1632.  
  1633.                 /*  finess the rect to print, we'll assume the the top left is always correct. */
  1634.                 /*  this helps with areas of the pict that don't fit entirely on one sheet of */
  1635.                 /*  paper */
  1636.                 
  1637.                 dstRect = srcRect;
  1638.                 
  1639.                 OffsetRect( &dstRect,
  1640.                             pageRect->left - srcRect.left,
  1641.                             pageRect->top  - srcRect.top );
  1642.  
  1643.                 ClipRect( &dstRect ) ;
  1644.                 
  1645.                 /* get the gworld pixmap and lock it down */
  1646.                 offPixMap = GetGWorldPixMap( theGWorld ) ;
  1647.                 (void) LockPixels( offPixMap ) ;
  1648.                 
  1649.                 /* copy from the gWorld Image to the window's port */
  1650.                 CopyBits( (BitMap *) *offPixMap,
  1651.                           &imagingPort->portBits,
  1652.                           &srcRect,                         
  1653.                           &dstRect,
  1654.                           srcCopy,
  1655.                           nil ) ;
  1656.                 
  1657.                 /* unlock the pixmap */
  1658.                 (void) UnlockPixels( offPixMap ) ;
  1659.  
  1660.             }
  1661.             
  1662.             /*  bump the page number */
  1663.             thisPage++ ;
  1664.         }
  1665.     }
  1666.         
  1667. }
  1668.  
  1669. /* ---------------------------------------------------------------------------------- */
  1670.  
  1671. OSErr DoPrintLoop( WindowPtr    theWindow ) 
  1672. {
  1673.     short                savedResFile = CurResFile() ;
  1674.     GrafPtr                savedPort ;
  1675.     TPPrPort            printingPort ;
  1676.     OSErr                theErr = noErr ;
  1677.     THPrint                thePrintRec  ;
  1678.     PrIdleUPP            myIdleProc = NewPrIdleProc(IdleProc) ;
  1679.     DocumentHdl         theDocumentHdl ;
  1680.     CountPagesProc        countPagesP ;
  1681.     PrintPageProc        printPageP ;
  1682.     
  1683.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  1684.     if(theDocumentHdl != NULL)
  1685.     {
  1686.         
  1687.         thePrintRec = (**theDocumentHdl).fPrintRec ; 
  1688.         
  1689.         GetPort( &savedPort ) ;
  1690.         PrOpen() ;
  1691.         
  1692.         if( (theErr = PrError()) == noErr ) {
  1693.         
  1694.             short    numCopies = (**thePrintRec).prJob.iCopies ;
  1695.             short    firstPage = (**thePrintRec).prJob.iFstPage ;    /*  save the first page */
  1696.             short    lastPage = (**thePrintRec).prJob.iLstPage;        /*  save the last page */
  1697.             short    copies, pageNum ;
  1698.             
  1699.             (**thePrintRec).prJob.iFstPage = 1 ;            /*  reset to 1 */
  1700.             (**thePrintRec).prJob.iLstPage = iPrPgMax ;    /*  reset to maximum */
  1701.  
  1702.             /*  we don't assign this directly because NewPrIdleProc may move memory, */
  1703.             /*  so assign to an intermediate - myIdleProc */
  1704.             (**thePrintRec).prJob.pIdleProc =  myIdleProc; /*  install the cursor spinning idle proc */
  1705.             
  1706.             /*
  1707.              * since the count pages function is dereferenced by a pointer we have two choices,
  1708.              * either lock the handle, or copy the function pointer.
  1709.              */
  1710.             countPagesP = (**theDocumentHdl).procs->countPagesP ;
  1711.             
  1712.             /* if there is one, call the save handling proc with this window */
  1713.             if( countPagesP )
  1714.                 lastPage = (*countPagesP)( theWindow, &(**thePrintRec).prInfo.rPage ) ;
  1715.             
  1716.             for( copies = 1; copies <= numCopies ; copies++ ) {
  1717.             
  1718.                 printingPort = PrOpenDoc( thePrintRec, nil, nil ) ;
  1719.                 SetPort( (GrafPtr)printingPort ) ;
  1720.                 if((theErr = PrError()) == noErr ) {
  1721.                 
  1722.                     for( pageNum = firstPage; pageNum <= lastPage; pageNum++ ) {
  1723.                     
  1724.                         PrOpenPage( printingPort, nil ) ;
  1725.                         if((theErr = PrError()) == noErr ) {
  1726.                             
  1727.                             /*
  1728.                              * since the print page function is dereferenced by a pointer 
  1729.                              * we have two choices, either lock the handle, or copy the 
  1730.                              * function pointer.
  1731.                              */
  1732.                             printPageP = (**theDocumentHdl).procs->printPageP ;
  1733.                             
  1734.                             /*  image the page */
  1735.                             if( printPageP )
  1736.                                 (*printPageP)( theWindow,  &(**thePrintRec).prInfo.rPage, (GrafPtr)printingPort, pageNum  ) ;
  1737.             
  1738.                             PrClosePage(printingPort) ;
  1739.                         }
  1740.                     
  1741.                     }
  1742.                     if( (theErr = PrError()) == noErr ) {
  1743.  
  1744.                         TPrStatus         theStatus ;
  1745.  
  1746.                         PrCloseDoc(printingPort) ;
  1747.                         theErr = PrError() ;
  1748.  
  1749.                         /*  if we're printing to our good friend the ImageWriter, or similar, despool */
  1750.                         if( theErr == noErr && ((**thePrintRec).prJob.bJDocLoop == bSpoolLoop))
  1751.                             PrPicFile( thePrintRec, nil, nil, nil, &theStatus ) ; 
  1752.                     }
  1753.                 }
  1754.             }
  1755.         }
  1756.         PrClose() ;
  1757.  
  1758.         DisposeRoutineDescriptor((UniversalProcPtr)myIdleProc) ;
  1759.  
  1760.         SetPort( savedPort ) ;
  1761.     }
  1762.  
  1763.     return theErr ;
  1764.     
  1765. }
  1766.  
  1767.  
  1768. /*------------------------------------------------------------ */
  1769.  
  1770. /*
  1771.  * called to register our AppleEvent handlers.
  1772.  *
  1773.  * Should really have some error handling in here.
  1774.  */
  1775. void RegisterRequiredAppleEventHandlers(void)
  1776. {
  1777.     OSErr                 theError;
  1778.     ProcessSerialNumber    myApplicationPSN;            /* This application's psn  */
  1779.     
  1780.     /* Set up a self-addressed descriptor record.  */
  1781.      myApplicationPSN.highLongOfPSN = 0;
  1782.      myApplicationPSN.lowLongOfPSN = kCurrentProcess ;
  1783.      
  1784.      theError = AECreateDesc(typeProcessSerialNumber,
  1785.                              (Ptr)&myApplicationPSN,
  1786.                              sizeof(ProcessSerialNumber),
  1787.                              &gSelfAddress);
  1788.     if (theError!=noErr)
  1789.         return;
  1790.     
  1791.     theError = AEInstallEventHandler(    kCoreEventClass,
  1792.                                         kAEOpenApplication,
  1793.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypeOAPP),
  1794.                                         0L,
  1795.                                         false);
  1796.     if (theError!=noErr)
  1797.         return;
  1798.                 
  1799.     theError = AEInstallEventHandler(    kCoreEventClass,
  1800.                                         kAEOpenDocuments,
  1801.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypeODOC),
  1802.                                         0L,
  1803.                                         false);
  1804.     if (theError!=noErr)
  1805.         return;
  1806.                 
  1807.     theError = AEInstallEventHandler(    kCoreEventClass,
  1808.                                         kAEPrintDocuments,
  1809.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypePDOC),
  1810.                                         0L,
  1811.                                         false);
  1812.     if (theError!=noErr)
  1813.         return;
  1814.                 
  1815.     theError = AEInstallEventHandler(    kCoreEventClass,
  1816.                                         kAEQuitApplication,
  1817.                                         NewAEEventHandlerProc(HandleCoreAppleEventOfTypeQUIT),
  1818.                                         0L,
  1819.                                         false);
  1820.     if (theError!=noErr)
  1821.         return;
  1822. }
  1823.  
  1824.  
  1825. /*------------------------------------------------------------ */
  1826.  
  1827. /*
  1828.  * open application theEventRecord handler for the core theEventRecord suite, 
  1829.  * by default we just want a blank new document
  1830.  */
  1831. pascal OSErr HandleCoreAppleEventOfTypeOAPP( AppleEvent *theAppleEvent, AppleEvent *theAppleEventReply, long userDefinedReferenceConstant)
  1832. {
  1833.     /*
  1834.      * we don't actually do anything on open - you could,
  1835.      * for example you might want to open a blank untitled 
  1836.      * theWindow
  1837.      */
  1838.     OSErr theError = noErr ;
  1839.     return theError;
  1840. }
  1841.  
  1842.  
  1843. /*------------------------------------------------------------ */
  1844.  
  1845. /*
  1846.  * handler for the open document AppleEvent handler
  1847.  */
  1848.  
  1849. pascal OSErr HandleCoreAppleEventOfTypeODOC(AppleEvent *theAppleEvent, AppleEvent *theAppleEventReply, long userDefinedReferenceConstant)
  1850. {
  1851.     FSSpec         theFileSpec;
  1852.     AEDescList    theDocumentList;
  1853.     OSErr        theError,
  1854.                 theIgnoredError;
  1855.     long        myTempIndex,
  1856.                 numberOfItemsInList;
  1857.     Size         actualSize;
  1858.     AEKeyword    theAEKeyword;
  1859.     DescType    theDescriptorType;
  1860.  
  1861.     
  1862.     theError = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&theDocumentList);
  1863.     if (theError == noErr) {
  1864.         /*
  1865.          * see how many descriptor items are in the list
  1866.          * this is the number of documents we want to open
  1867.          */
  1868.         theError = AECountItems(&theDocumentList,&numberOfItemsInList);
  1869.         
  1870.         /*
  1871.          * now get each descriptor record from the list
  1872.          * coerce the returned data to an FSSpec record, and
  1873.          * open the asoociated file
  1874.          */
  1875.         for (myTempIndex=1; myTempIndex <= numberOfItemsInList && theError == noErr; myTempIndex++) {
  1876.         
  1877.             theError = AEGetNthPtr(    &theDocumentList, 
  1878.                                     myTempIndex,
  1879.                                     typeFSS,
  1880.                                     &theAEKeyword,
  1881.                                     &theDescriptorType,
  1882.                                     (Ptr)&theFileSpec,
  1883.                                     sizeof(theFileSpec),
  1884.                                     &actualSize);
  1885.     
  1886.             if (theError == noErr)    {
  1887.             
  1888.                 FInfo        fndrInfo ;
  1889.                 
  1890.                 /*
  1891.                  * we now have a valid FSSpec to reference the file, we need to know 
  1892.                  * what type the file is to determine which file open function to call
  1893.                  * we can determine this from the finder info for the file
  1894.                  */
  1895.                 
  1896.                 theError = FSpGetFInfo( &theFileSpec, &fndrInfo );    
  1897.                 
  1898.                 /*
  1899.                  * if we got that ok, then we switch on the file  
  1900.                  * type (we don't care about the creator type)    
  1901.                  */
  1902.                         
  1903.                 if (theError == noErr)    {
  1904.                 
  1905.                     switch( fndrInfo.fdType ) {
  1906.                         case 'TEXT':    /* your app should NOT really open text files since
  1907.                                          * they may not be of type 3DMF, this is here for 
  1908.                                          * debugging, note that the standard file dlog will
  1909.                                          * not allow you to open TEXT files.
  1910.                                          */
  1911.                         case '3DMF':
  1912.                             ViewerWindow_Open( &theFileSpec );
  1913.                             break ;
  1914.                     }
  1915.                 }
  1916.             }
  1917.         }
  1918.         theIgnoredError = AEDisposeDesc(&theDocumentList);
  1919.     }
  1920.     return theError ;
  1921. }
  1922.  
  1923. /*------------------------------------------------------------ */
  1924.  
  1925. /*
  1926.  * handler for the print document theEventRecord handler
  1927.  */
  1928. pascal OSErr HandleCoreAppleEventOfTypePDOC(AppleEvent *theAppleEvent,AppleEvent *theAppleEventReply,long userDefinedReferenceConstant)
  1929. {
  1930.     FSSpec         theFileSpec;
  1931.     AEDescList    theDocumentList;
  1932.     OSErr        theError;
  1933.     long        myTempIndex,
  1934.                 numberOfItemsInList;
  1935.     Size         actualSize;
  1936.     AEKeyword    theAEKeyword;
  1937.     DescType    theDescriptorType;
  1938.  
  1939.     
  1940.     theError = AEGetParamDesc(theAppleEvent,keyDirectObject,typeAEList,&theDocumentList);
  1941.     if (theError == noErr) {    
  1942.         
  1943.         /*
  1944.          * see how many descriptor items are in the list
  1945.          * this is the number of documents we want to print
  1946.          */
  1947.         
  1948.         theError = AECountItems(&theDocumentList,&numberOfItemsInList);
  1949.  
  1950.         /*
  1951.          * now get each descriptor record from the list
  1952.          * coerce the returned data to an FSSpec record, and
  1953.          * print the asoociated file
  1954.          */
  1955.         
  1956.         for (myTempIndex=1; myTempIndex <= numberOfItemsInList && theError == noErr; myTempIndex++) {
  1957.         
  1958.             theError = AEGetNthPtr(    &theDocumentList, 
  1959.                                 myTempIndex,
  1960.                                 typeFSS,
  1961.                                 &theAEKeyword,
  1962.                                 &theDescriptorType,
  1963.                                 (Ptr)&theFileSpec,
  1964.                                 sizeof(theFileSpec),
  1965.                                 &actualSize);
  1966.     
  1967.             if (theError == noErr)    {    
  1968.                             
  1969.                 /*
  1970.                  * if the app handles printing then you could do 
  1971.                  * something like: theError = HandlePrintDoc( &theFileSpec );
  1972.                  */
  1973.                 
  1974.                 theError = errAEEventNotHandled ;
  1975.             }
  1976.         }
  1977.         theError = AEDisposeDesc(&theDocumentList);
  1978.     }
  1979.     return theError ;
  1980. }
  1981.  
  1982. /*------------------------------------------------------------ */
  1983.  
  1984. /*
  1985.  * Quit AppleEvent handler
  1986.  */
  1987.  
  1988. pascal OSErr HandleCoreAppleEventOfTypeQUIT(AppleEvent *theAppleEvent,AppleEvent *theAppleEventReply,long userDefinedReferenceConstant)
  1989. {
  1990.     OSErr             theError = noErr ;        /* this is used as the return value  */
  1991.  
  1992.     theError = HandleFileQuitItem() ;
  1993.             
  1994.     return theError ;
  1995. }
  1996.  
  1997. /*------------------------------------------------------------ */
  1998.  
  1999. /*
  2000.  * we want to handle events until the fronmost theWindow goes away
  2001.  */
  2002.  
  2003. void MainEventLoop( void )
  2004. {
  2005.     EventRecord     theEventRecord;
  2006.  
  2007.     while( !gQuitFlag )
  2008.     {
  2009.         Point            mouseLoc ;
  2010.         
  2011.         if (WaitNextEvent( everyEvent, &theEventRecord,  GetCaretTime(), NULL ))
  2012.         {
  2013.             AdjustMenus() ;
  2014.             ( void ) HandleEvent( &theEventRecord ) ;
  2015.         }
  2016.     }
  2017. }
  2018.  
  2019. /*------------------------------------------------------------ */
  2020.  
  2021. /*
  2022.  * actually handle the event, this function can also be used for 
  2023.  * the anchor for the renderer.
  2024.  */
  2025.  
  2026.  
  2027. TQ3Boolean HandleEvent( const EventRecord *theEventRecord )
  2028. {
  2029.     WindowPtr           theWindow;
  2030.     GrafPtr                savedPort ;
  2031.     short               thePart;
  2032.     Rect                screenRect;
  2033.     Rect                growRect ;
  2034.     Point                aPoint = {100, 100};
  2035.     GrafPtr                oldPort ;
  2036.     Boolean                eventWasHandled = false ;
  2037.     unsigned long        width ;
  2038.     unsigned long        height ;
  2039.     long                newSize ;
  2040.     OSErr                theErr ;
  2041.     Point                mouseLoc ;
  2042.     TQ3Boolean             handledEvent = kQ3False ;
  2043.     TQ3ViewerObject        theViewer = NULL ;
  2044.     ViewerDataHdl        theViewerDataHdl ;
  2045.     DocumentHdl            theDocumentHdl ;
  2046.     UpdateContentProc    theUpdateProc ;
  2047.     HandleEventProc        theEventProc ;
  2048.     CloseProc            closeP ;
  2049.         
  2050.     SetCursor( &qd.arrow ) ;
  2051.             
  2052.     switch (theEventRecord->what) 
  2053.     {
  2054.         case mouseDown:
  2055.         
  2056.             /* we set up thePart in the window test at the top of this routine */
  2057.             thePart = FindWindow ( theEventRecord->where, &theWindow ) ;
  2058.  
  2059.             switch( thePart ) {
  2060.                 case inMenuBar: 
  2061.                     HandleMenuCommand(MenuSelect(theEventRecord->where));
  2062.                     handledEvent = kQ3True ;
  2063.                     break;
  2064.                 
  2065.                 case inDrag:
  2066.             
  2067.                     screenRect = (**GetGrayRgn()).rgnBBox;
  2068.                     DragWindow( theWindow, theEventRecord->where, &screenRect );
  2069.                     handledEvent = kQ3True ;
  2070.                     break ;
  2071.             
  2072.                 case inContent:
  2073.             
  2074.                     if (theWindow != FrontWindow()) 
  2075.                     {
  2076.                         SelectWindow( theWindow );
  2077.                         handledEvent = kQ3True ;
  2078.                     }
  2079.                     else
  2080.                     {
  2081.                         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2082.                         
  2083.                         /*
  2084.                          * since the update function is dereferenced by a pointer we have two choices,
  2085.                          * either lock the handle, or copy the function pointer.
  2086.                          */
  2087.                         theEventProc = (**theDocumentHdl).procs->handleEventP ;
  2088.                         
  2089.                         /* if there is one, call the event handling proc with this window */
  2090.                         if( theEventProc )
  2091.                             handledEvent = (*theEventProc)( theWindow, theEventRecord ) ;
  2092.                         else
  2093.                             handledEvent = kQ3False ;
  2094.                     }
  2095.                     break ;
  2096.             
  2097.                 case inGrow:
  2098.                 
  2099.                     /*
  2100.                      * get the viewer object associated with this window
  2101.                      */
  2102.                     
  2103.                     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2104.                     if(theDocumentHdl != NULL) 
  2105.                     {
  2106.                         if((**theDocumentHdl).fDocumentMagic == kViewerMagic 
  2107.                             && (theViewerDataHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL
  2108.                             && (theViewer = (**theViewerDataHdl).fViewer) != NULL )
  2109.                         {
  2110.                             
  2111.                             /* 
  2112.                              * first we need to calculate the minimum size 
  2113.                              * for this viewer window, fortunately the
  2114.                              * viewer library has a handy little utility
  2115.                              * function that we can use here:
  2116.                              */
  2117.                             
  2118.                             
  2119.                             GetPort( &savedPort ) ;
  2120.                             SetPort( (GrafPtr)theWindow ) ;
  2121.                             
  2122.                             theErr = Q3ViewerGetMinimumDimension( 
  2123.                                         theViewer,
  2124.                                         &width,
  2125.                                         &height );
  2126.  
  2127.                             growRect.top = height + LMGetMBarHeight() ; /* the height of tuhe title bar is the same as the height of the menu bar */
  2128.                             growRect.left = width + 34;        /* +34 so the grow box look neat */
  2129.                             growRect.bottom = kMaxHeight ;
  2130.                             growRect.right = kMaxWidth ;        
  2131.                             
  2132.                             newSize = GrowWindow(theWindow, theEventRecord->where, &growRect);
  2133.                             if (newSize != 0) {
  2134.                                 width = LoWrd(newSize) ;
  2135.                                 height = HiWrd(newSize) ;
  2136.                                 SizeWindow(theWindow, width, height, true);
  2137.                                 Q3ViewerSetBounds( theViewer, &theWindow->portRect ) ;
  2138.                                 
  2139.                                 EraseRect( &theWindow->portRect ) ;
  2140.                                 Q3ViewerDraw( theViewer ) ;
  2141.                                 DoDrawGrowIcon( theWindow ) ;
  2142.                                 
  2143.                             }
  2144.                             handledEvent = kQ3True ;
  2145.                             SetPort( savedPort ) ;
  2146.  
  2147.                         }
  2148.                     }
  2149.                     break;
  2150.                     
  2151.                 case inGoAway:
  2152.                     if (TrackGoAway( theWindow, theEventRecord->where )) {
  2153.                         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2154.                         closeP = (**theDocumentHdl).procs->closeP ;
  2155.                         if( closeP )
  2156.                             (*closeP)( theWindow ) ;
  2157.                     }
  2158.                     handledEvent = kQ3True ;
  2159.                     break ;
  2160.                     
  2161.                 default:
  2162.                     break ;
  2163.             }
  2164.             break ;
  2165.                     
  2166.                 
  2167.         case updateEvt:
  2168.  
  2169.             handledEvent = kQ3True  ;
  2170.  
  2171.             theWindow = (WindowPtr)theEventRecord->message;
  2172.             theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2173.             
  2174.             /*
  2175.              * since the update function is dereferenced by a pointer we have two choices,
  2176.              * either lock the handle, or copy the finction pointer.
  2177.              */
  2178.             theUpdateProc = (**theDocumentHdl).procs->updateWindowP ;
  2179.             
  2180.             /* call the update proc with this window */
  2181.             if( theUpdateProc )
  2182.                 (*theUpdateProc)(theWindow) ;
  2183.                 
  2184.             break ;
  2185.             
  2186.         case keyDown:
  2187.         case autoKey:
  2188.             HandleKeyPress(theEventRecord);
  2189.             handledEvent = kQ3True ;
  2190.             break ;
  2191.             
  2192.         case diskEvt:
  2193.             if ( HiWrd(theEventRecord->message) != noErr ) 
  2194.                 (void) DIBadMount(aPoint, theEventRecord->message) ;
  2195.             handledEvent = kQ3True ;
  2196.             break ;
  2197.             
  2198.         case osEvt:
  2199.         case activateEvt:
  2200.             handledEvent = kQ3False  ;
  2201.             break ;
  2202.  
  2203.         case kHighLevelEvent:
  2204.             AEProcessAppleEvent(theEventRecord);
  2205.             handledEvent = kQ3True ;
  2206.             break ;
  2207.     }
  2208.  
  2209. Done:
  2210.     return handledEvent ;
  2211. }
  2212.  
  2213.  
  2214. /*------------------------------------------------------------ */
  2215.  
  2216. /*
  2217.  * handle keydow events, all we do is dispatch to the 
  2218.  * menu handler if the command key is down, otherwise
  2219.  * the keypress is ignored.
  2220.  */
  2221.  
  2222. void HandleKeyPress(const EventRecord *theEventRecord)
  2223. {
  2224.     char    key;
  2225.  
  2226.     key = theEventRecord->message & charCodeMask;
  2227.     
  2228.     /* check to see if we selected a menu  */
  2229.     if ( theEventRecord->modifiers & cmdKey ) {        /* Command key down?  */
  2230.         HandleMenuCommand(MenuKey(key));
  2231.     } 
  2232. }
  2233.  
  2234.  
  2235. /*------------------------------------------------------------ */
  2236.  
  2237. /*
  2238.  * handle menu commands
  2239.  */
  2240.  
  2241. void HandleMenuCommand(long menuResult)
  2242. {
  2243.     short        menuID;
  2244.     short        menuItem;
  2245.  
  2246.     menuID = HiWrd(menuResult);
  2247.     menuItem = LoWrd(menuResult);
  2248.  
  2249.     switch ( menuID ) {
  2250.     
  2251.         case mInteractiveRendererMenu:
  2252.             HandleInteractiveRendererMenu( menuItem ) ;
  2253.             break ;
  2254.             
  2255.         case mAppleMenu:
  2256.             HandleAppleMenu( menuItem ) ;
  2257.             break ;
  2258.             
  2259.         case mFileMenu:
  2260.             HandleFileMenu( menuItem ) ;
  2261.             break;
  2262.         
  2263.         case mEditMenu:
  2264.             HandleEditMenu( menuItem ) ;
  2265.             break ;
  2266.             
  2267.         case mViewMenu:
  2268.             HandleViewMenu( menuItem ) ;
  2269.             break ;
  2270.  
  2271.     }
  2272.     HiliteMenu(0);        // Unhighlight whatever MenuSelect or MenuKey hilited
  2273. }
  2274.  
  2275.  
  2276.  
  2277. /*------------------------------------------------------------ */
  2278.  
  2279. /*
  2280.  * handle menu commands in the apple menu
  2281.  */
  2282.  
  2283.  
  2284. void HandleAppleMenu( short menuItem )
  2285. {
  2286.     Str255        daName;
  2287.     DialogPtr    theDialog ; 
  2288.     short        itemHit ;
  2289.     
  2290.     switch ( menuItem ) {
  2291.         ModalFilterUPP         theProc ;
  2292.  
  2293.         case iAppleAboutItem:
  2294.             
  2295.             theDialog = GetNewDialog ( kAboutDialogID, NULL, (WindowPtr)-1 );
  2296.             
  2297.             GetStdFilterProc( &theProc ) ;
  2298.             SetDialogDefaultItem(theDialog, ok) ;
  2299.             do {
  2300.                 ModalDialog ( theProc, &itemHit );
  2301.             } while( itemHit != ok ) ;
  2302.             DisposeDialog ( theDialog );
  2303.             
  2304.             break;
  2305.             
  2306.         default:
  2307.             GetMenuItemText(GetMenuHandle(mAppleMenu), menuItem, daName);
  2308.             (void) OpenDeskAcc(daName);
  2309.             break;
  2310.     }
  2311. }
  2312.  
  2313. /*------------------------------------------------------------ */
  2314.  
  2315. /*
  2316.  * handle menu commands in the file menu
  2317.  */
  2318.  
  2319.  
  2320. void HandleFileMenu( short menuItem )
  2321. {
  2322.     WindowPtr            theWindow ;
  2323.     StandardFileReply    theSFReply ;
  2324.     DocumentHdl            theDocumentHdl ;
  2325.     SaveAsProc            saveAsP ;
  2326.     SaveProc            saveP ;
  2327.     RevertProc            revertP ;
  2328.     CloseProc            closeP ;
  2329.     PrePrintProc        prePrintP ;
  2330.     PostPrintProc        postPrintP ;
  2331.  
  2332.     switch ( menuItem ) {
  2333.     
  2334.         case iFileNewItem:
  2335.         
  2336.             ViewerWindow_New( "\pViewer Window" ) ;
  2337.             break ;
  2338.     
  2339.         case iFileSaveAsItem:
  2340.         
  2341.             if( (theWindow = FrontWindow()) != NULL )
  2342.             {
  2343.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2344.                 
  2345.                 /*
  2346.                  * since the save function is dereferenced by a pointer we have two choices,
  2347.                  * either lock the handle, or copy the function pointer.
  2348.                  */
  2349.                 saveAsP = (**theDocumentHdl).procs->saveAsP ;
  2350.                 
  2351.                 /* if there is one, call the save handling proc with this window */
  2352.                 if( saveAsP )
  2353.                     (*saveAsP)( theWindow ) ;
  2354.                 
  2355.             }
  2356.             break ;
  2357.  
  2358.         case iFileSaveItem:
  2359.             if( (theWindow = FrontWindow()) != NULL )
  2360.             {
  2361.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2362.                 
  2363.                 /*
  2364.                  * since the save function is dereferenced by a pointer we have two choices,
  2365.                  * either lock the handle, or copy the function pointer.
  2366.                  */
  2367.                 saveP = (**theDocumentHdl).procs->saveP ;
  2368.                 
  2369.                 /* if there is one, call the save handling proc with this window */
  2370.                 if( saveP )
  2371.                     (*saveP)( theWindow ) ;
  2372.                 
  2373.             }
  2374.             break ;
  2375.             
  2376.         
  2377.         case iFileRevertItem:
  2378.             if( (theWindow = FrontWindow()) != NULL )
  2379.             {
  2380.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2381.                 
  2382.                 /*
  2383.                  * since the revert function is dereferenced by a pointer we have two choices,
  2384.                  * either lock the handle, or copy the function pointer.
  2385.                  */
  2386.                 revertP = (**theDocumentHdl).procs->revertP ;
  2387.                 
  2388.                 /* if there is one, call the revert handling proc with this window */
  2389.                 if( revertP )
  2390.                     (*revertP)( theWindow ) ;
  2391.                 
  2392.             }
  2393.             break ;
  2394.         
  2395.         /* these need to be converted */
  2396.         case iFilePageSetupItem:
  2397.             if( (theWindow = FrontWindow()) != NULL )
  2398.             {
  2399.                 THPrint        thePrintRec ;
  2400.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2401.                 
  2402.                 thePrintRec = (**theDocumentHdl).fPrintRec ;
  2403.                 DoStyleDlog( thePrintRec ) ;
  2404.             }
  2405.             break ;
  2406.         
  2407.         case iFilePrintItem:
  2408.             if( (theWindow = FrontWindow()) != NULL )
  2409.             {
  2410.                 THPrint        thePrintRec ;
  2411.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2412.                 
  2413.                 thePrintRec = (**theDocumentHdl).fPrintRec ;
  2414.                 if( DoJobDlog( thePrintRec ) == noErr )
  2415.                 {
  2416.                 
  2417.                     /*
  2418.                      * since the preprint function is dereferenced by a pointer we have two choices,
  2419.                      * either lock the handle, or copy the function pointer.
  2420.                      */
  2421.                     prePrintP = (**theDocumentHdl).procs->prePrintP ;
  2422.                     
  2423.                     /* if there is one, call the revert handling proc with this window */
  2424.                     if( prePrintP )
  2425.                         (*prePrintP)( theWindow ) ;
  2426.                         
  2427.                     DoPrintLoop( theWindow ) ;
  2428.                     
  2429.                     postPrintP = (**theDocumentHdl).procs->postPrintP ;
  2430.                     
  2431.                     /* if there is one, call the revert handling proc with this window */
  2432.                     if( postPrintP )
  2433.                         (*postPrintP)( theWindow ) ;
  2434.                 }
  2435.                 
  2436.             }
  2437.             break ;
  2438.                 
  2439.         case iFileOpenItem:
  2440.         
  2441.             /* currently we only open 3dmf files */
  2442.             /* Get the file name to open  */
  2443.             StandardGetFile( NULL, kNumTypes, kTypeList, &theSFReply ) ;
  2444.     
  2445.             /* did the user cancel?  */
  2446.             if(theSFReply.sfGood)
  2447.                 ViewerWindow_Open( &theSFReply.sfFile ) ; /* no - process the file  */
  2448.                 
  2449.             break ;
  2450.             
  2451.         case iFileCloseItem:
  2452.             if( (theWindow = FrontWindow()) != NULL )
  2453.             {
  2454.                 theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2455.                 
  2456.                 /*
  2457.                  * since the revert function is dereferenced by a pointer we have two choices,
  2458.                  * either lock the handle, or copy the function pointer.
  2459.                  */
  2460.                 closeP = (**theDocumentHdl).procs->closeP ;
  2461.                 
  2462.                 /* if there is one, call the revert handling proc with this window */
  2463.                 if( closeP )
  2464.                     (*closeP)( theWindow ) ;
  2465.                 
  2466.             }
  2467.             break ;
  2468.             
  2469.         case iFileQuitItem:
  2470.             HandleFileQuitItem();
  2471.             break;
  2472.     }
  2473.  
  2474. }
  2475.  
  2476.  
  2477. /*------------------------------------------------------------ */
  2478.  
  2479.  
  2480. /*
  2481.  * handles the Quit menu item in the file menu
  2482.  */
  2483.  
  2484. OSErr HandleFileQuitItem( void ) 
  2485. {
  2486.     OSErr             theError = noErr ;        /* this is used as the return value  */
  2487.     WindowPtr        theWindow ;
  2488.     Boolean            tempQuitFlag = true ;
  2489.     CloseProc        closeP ;
  2490.     DocumentHdl        theDocumentHdl ;
  2491.  
  2492.     /*
  2493.      * if the application has any open windows, close them before 
  2494.      * tempQuitFlag.  Since the user may cancelduring the process of 
  2495.      * closing, make sure we don't quit the app, unless they can 
  2496.      * be closed
  2497.      */
  2498.     while(( theWindow = FrontWindow()) != NULL && tempQuitFlag )
  2499.     {
  2500.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2501.         
  2502.         /*
  2503.          * since the save function is dereferenced by a pointer we have two choices,
  2504.          * either lock the handle, or copy the function pointer.
  2505.          */
  2506.         closeP = (**theDocumentHdl).procs->closeP ;
  2507.         
  2508.         /* if there is one, call the save handling proc with this window */
  2509.         if( closeP )
  2510.             tempQuitFlag = ((*closeP)( theWindow ) == noErr)  ;            
  2511.     }
  2512.  
  2513.     /*
  2514.      * if we closed everything up successfully, return noErr, otherwise
  2515.      * indicate to the caller of this function that we canceled
  2516.      */
  2517.     
  2518.     if (tempQuitFlag) {
  2519.         gQuitFlag = true;                    /* in other word the user didn't cancel  */
  2520.          AEDisposeDesc(&gSelfAddress);        /* don't forget to dispose of the        */
  2521.     }
  2522.     else {
  2523.         theError = userCanceledErr ;
  2524.     }
  2525.     
  2526.     return theError ;
  2527.  
  2528. }
  2529.  
  2530. /*------------------------------------------------------------ */
  2531.  
  2532. /*
  2533.  * handle menu commands in the edit menu
  2534.  *
  2535.  * To Do: each menu command needs to be factored into the list of procs
  2536.  *        for the document type.
  2537.  */
  2538.  
  2539.  
  2540. void HandleEditMenu( short menuItem )
  2541. {
  2542.     DocumentHdl            theDocumentHdl ;
  2543.     ViewerDataHdl        theViewerHdl ;
  2544.  
  2545.     WindowPtr            theWindow ;
  2546.     TQ3ViewerObject        theViewer ;
  2547.     OSErr                theError ;
  2548.     GrafPtr                savedPort ;
  2549.     
  2550.     CutProc                cutProc ;            /* handle clipboard cut, same as copy followed by clear */
  2551.     CopyProc            copyProc ;            /* handle clipboard copy */
  2552.     PasteProc            pasteProc ;            /* paste compatible scrap type from the scrap */
  2553.     ClearProc            clearProc ;            /* clear the document contents without a save to the scrap */
  2554.     UndoProc            undoProc ;            /* undo the last action - if supported */
  2555.     
  2556.     /*
  2557.      * because we do this we are assuming that this menu is disabled for the
  2558.      * case where there is no window.
  2559.      */
  2560.     theWindow = FrontWindow() ;
  2561.     SetPort((GrafPtr)theWindow) ;
  2562.     if( theWindow != NULL )
  2563.     {
  2564.         long                 aLong ;
  2565.         
  2566.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2567.                 
  2568.         switch ( menuItem ) 
  2569.         {
  2570.             
  2571.             case iEditUndoItem:
  2572.                 undoProc = (**theDocumentHdl).procs->undoProc ;
  2573.                 /* if there is one, call the undo handling proc with this window */
  2574.                 if( undoProc )
  2575.                     (*undoProc)( theWindow ) ;
  2576.                 
  2577.                 /* redraw the content region of the window to reflect the change */
  2578.                 GetPort( &savedPort ) ;    
  2579.                 SetPort( theWindow ) ;
  2580.                 InvalRect( &theWindow->portRect ) ;
  2581.                 SetPort( savedPort ) ;
  2582.                 break ;
  2583.                 
  2584.             case iEditCutItem:
  2585.                 cutProc = (**theDocumentHdl).procs->cutProc ;
  2586.                 /* if there is one, call the cut handling proc with this window */
  2587.                 if( cutProc )
  2588.                     (*cutProc)( theWindow ) ;
  2589.                 aLong = UnloadScrap();
  2590.                 break ;
  2591.                 
  2592.             case iEditCopyItem:
  2593.                 copyProc = (**theDocumentHdl).procs->copyProc ;
  2594.                 /* if there is one, call the copy handling proc with this window */
  2595.                 if( copyProc )
  2596.                     (*copyProc)( theWindow ) ;
  2597.                 aLong = UnloadScrap();
  2598.                 break ;
  2599.                 
  2600.             case iEditPasteItem:
  2601.                 pasteProc = (**theDocumentHdl).procs->pasteProc ;
  2602.                 /* if there is one, call the paste handling proc with this window */
  2603.                 if( pasteProc )
  2604.                     (*pasteProc)( theWindow ) ;
  2605.                 aLong = UnloadScrap();
  2606.                 break ;
  2607.                 
  2608.             case iEditClearItem:
  2609.                 clearProc = (**theDocumentHdl).procs->clearProc ;
  2610.                 /* if there is one, call the clear handling proc with this window */
  2611.                 if( clearProc )
  2612.                     (*clearProc)( theWindow ) ;
  2613.                 aLong = UnloadScrap();
  2614.                 break ;        
  2615.             
  2616.             case iEditRendererPrefsItem:
  2617.                 {
  2618.                     /* this should probably be factored out somewhere */
  2619.                     TQ3RendererObject       qd3dRenderer;
  2620.                     TQ3ViewObject           qd3dView;   
  2621.                     TQ3Status               qd3dStatus;
  2622.                     TQ3Boolean              qd3dCanceled;
  2623.                     TQ3DialogAnchor         qd3dAnchor ;
  2624.                                         
  2625.                     /*
  2626.                      * get the reference to our viewer document data structure
  2627.                      * from the long reference constant for the window.  Cast
  2628.                      * it to the appropriate type.  If we can't get it (i.e. it's
  2629.                      * null we want to bail
  2630.                      */
  2631.                     if(theDocumentHdl != NULL  
  2632.                         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  2633.                         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL)
  2634.                     {
  2635.                         
  2636.                         /* get the reference to the viewer object from our data structure  */
  2637.                         theViewer = (**theViewerHdl).fViewer ;
  2638.                         if(theViewer == NULL) 
  2639.                             return ;
  2640.                         
  2641.                         /* Get the renderer */
  2642.                         qd3dView = Q3ViewerGetView(theViewer);
  2643.                         qd3dStatus = Q3View_GetRenderer(qd3dView, &qd3dRenderer);
  2644.  
  2645.                         /* Put up the configure dialog */
  2646.                         if (Q3Renderer_HasModalConfigure(qd3dRenderer))
  2647.                         {
  2648.                             /* this will be modal */
  2649.                             qd3dAnchor.clientEventHandler = NULL;
  2650.                             qd3dStatus = Q3Renderer_ModalConfigure(
  2651.                                                     qd3dRenderer,
  2652.                                                     qd3dAnchor,
  2653.                                                     &qd3dCanceled);
  2654.                         }
  2655.  
  2656.                         /* Clean up */
  2657.                         qd3dStatus = Q3Object_Dispose(qd3dRenderer);
  2658.                         /*
  2659.                          * assume that the renderer prefs changed something 
  2660.                          * so redraw the content region of the window 
  2661.                          */
  2662.                         GetPort( &savedPort ) ;
  2663.                         SetPort( theWindow ) ;
  2664.                         InvalRect( &theWindow->portRect ) ;
  2665.                         SetPort( savedPort ) ;
  2666.                     }
  2667.                 }
  2668.                 break;
  2669.         }
  2670.     }
  2671.  
  2672. }
  2673.  
  2674. /*------------------------------------------------------------ */
  2675.  
  2676. /*
  2677.  * utility function to get the viewer object 
  2678.  * associated with a particular viewer window
  2679.  */
  2680.  
  2681.  
  2682. TQ3ViewerObject    GetViewerFromViewerWindow( WindowPtr theWindow )
  2683. {
  2684.     OSErr                theError = paramErr ;
  2685.     short                theRef ;
  2686.     TQ3ViewerObject        theViewer = NULL ;
  2687.     FSSpec                theFSSpec ;
  2688.     DocumentHdl            theDocumentHdl ;
  2689.     
  2690.     if( theWindow != NULL )        /* sanity check  */
  2691.     {
  2692.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2693.         if(theDocumentHdl != NULL  
  2694.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  2695.         {
  2696.             /* get the viewer object from the document */
  2697.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  2698.             if( theViewerHdl != NULL )
  2699.             {
  2700.                 theViewer = (**theViewerHdl).fViewer ;
  2701.             }
  2702.         }
  2703.     }
  2704.     return theViewer ;
  2705. }
  2706.  
  2707. /*------------------------------------------------------------ */
  2708.  
  2709. /*
  2710.  * utility function to get the GWorld object 
  2711.  * associated with a particular pict window
  2712.  */
  2713.  
  2714.  
  2715. GWorldPtr GetGWorldFromPictWindow( WindowPtr  theWindow ) 
  2716. {
  2717.     DocumentHdl            theDocumentHdl ;
  2718.     PictDataHdl            thePictDataHdl ;
  2719.     GWorldPtr            theGWorld = NULL;
  2720.     OSErr                theErr ;
  2721.     
  2722.     if( theWindow != NULL )        /* sanity check  */
  2723.     {
  2724.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  2725.         if(theDocumentHdl != NULL
  2726.             && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  2727.             && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  2728.         {
  2729.             theGWorld = (**thePictDataHdl).fGWorld;
  2730.         }
  2731.     }
  2732.     return theGWorld ;
  2733. }
  2734. /*------------------------------------------------------------ */
  2735.  
  2736. /*
  2737.  * utility function to get the renderer associated with a particular
  2738.  * type.  Does a linear search of the pRendererList array to 
  2739.  * retrieve the renderer object associated with the type passed in.
  2740.  * Will return NULL if the renderer type is not in the list.
  2741.  */
  2742. TQ3RendererObject    GetRendererByType(TQ3ObjectType theRendererType)
  2743. {
  2744.     TQ3RendererObject    myRenderer = NULL ;
  2745.     long                theIndex ;
  2746.     
  2747.     for( theIndex = 0; theIndex < pRendererCount; theIndex++ ) 
  2748.     {
  2749.         if( pRendererList[ theIndex ].fRendererType    == theRendererType )
  2750.             myRenderer = pRendererList[ theIndex ].fRendererObject ;
  2751.     }
  2752.     return myRenderer ;
  2753. }
  2754.  
  2755. /*------------------------------------------------------------ */
  2756.  
  2757. /*
  2758.  * utility function to set the renderer for a viewer
  2759.  */
  2760.  
  2761. TQ3Status    ViewerSetRenderer( TQ3ObjectType theRendererType, TQ3ViewerObject theViewer )
  2762. {
  2763.     TQ3RendererObject    myRenderer = NULL ;
  2764.     long                theIndex ;
  2765.     TQ3ViewObject         myView ;
  2766.     TQ3Status            myStatus = kQ3Failure;
  2767.     OSErr                theError ;
  2768.     
  2769.     
  2770.     myRenderer = GetRendererByType( theRendererType ) ;
  2771.         
  2772.     /*
  2773.      * set the renderer for the view
  2774.      */
  2775.     myView = Q3ViewerGetView( theViewer );
  2776.     if( myView != NULL && myRenderer != NULL )
  2777.     {
  2778.         /* set the renderer to the one recovered in the loop above  */
  2779.         myStatus = Q3View_SetRenderer(myView, myRenderer) ;
  2780.         
  2781.     }
  2782.     return myStatus ;
  2783.  
  2784. }
  2785. /*------------------------------------------------------------ */
  2786.  
  2787. /*
  2788.  * handle menu commands in the renderer menu
  2789.  */
  2790.  
  2791.  
  2792. void HandleInteractiveRendererMenu( short menuItem )
  2793. {
  2794.     WindowPtr            theWindow ;
  2795.     TQ3ObjectType        theRendererType ;
  2796.     TQ3ViewerObject        theViewer ;
  2797.     GrafPtr                savedPort ;
  2798.     
  2799.     theWindow = FrontWindow() ;
  2800.  
  2801.     if( theWindow != NULL )
  2802.     {
  2803.         theViewer = GetViewerFromViewerWindow( theWindow ) ;    
  2804.         theRendererType = pInteractiveTypes[ menuItem - 1 ] ;
  2805.         ViewerSetRenderer( theRendererType, theViewer ) ;
  2806.         GetPort(&savedPort) ;
  2807.         SetPort((GrafPtr)theWindow) ;
  2808.         InvalRect(&theWindow->portRect) ;
  2809.         SetPort(savedPort) ;
  2810.     }
  2811. }
  2812.  
  2813.  
  2814.  
  2815. /*------------------------------------------------------------ */
  2816.  
  2817. /*
  2818.  * The user chose to render with a non interactive renderer, put
  2819.  * up a dialog to allow them to select and configure the renderer
  2820.  * and copy the appropriate values from the current viewer window.
  2821.  */
  2822.  
  2823.  
  2824. pascal Boolean OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit)
  2825. {
  2826.  
  2827.     ModalFilterUPP         theProc ;
  2828.     Boolean                retVal ;
  2829.     
  2830.     static    Boolean        isDisabled = false ;
  2831.     OSErr                theErr = noErr ;
  2832.     
  2833.     /* stuff for getditems etc */
  2834.     Str255                theItem ;
  2835.     short                iKind;
  2836.     Handle                iHandle;
  2837.     Rect                iRect;
  2838.     char                theKey ;
  2839.     
  2840.     
  2841.     /* get the std filter proc */
  2842.     
  2843.     theErr = GetStdFilterProc( &theProc ) ;
  2844.     
  2845.     if( theErr != noErr )
  2846.         ExitToShell() ;
  2847.         
  2848.     /* try to call the standard filter, if it handles the event, we don't */
  2849.     if( !(retVal = CallModalFilterProc(theProc, dlg, event, itemHit)) )
  2850.     {
  2851.         switch (event->what) {
  2852.     
  2853.             case nullEvent:
  2854.                 break;
  2855.     
  2856.             case keyDown:
  2857.             case autoKey:
  2858.                   theKey = event->message & charCodeMask;
  2859.         
  2860.                 if( isalpha(theKey) || ispunct(theKey) || isspace(theKey) ) 
  2861.                 {
  2862.                     /* It's not a number, reject it */
  2863.                     SysBeep(1);
  2864.                     
  2865.                     /* tell the dialog manager that we handled this already and 
  2866.                      * it doesn't have to, so the keystroke will _not_ get 
  2867.                      * added to the edit line 
  2868.                      */
  2869.                     retVal = true; 
  2870.                 }
  2871.                 else
  2872.                     retVal = false;
  2873.                     
  2874.                 break ;
  2875.     
  2876.             case updateEvt:
  2877.                 PenPat( &qd.ltGray ) ;
  2878.                 
  2879.                 /* get the text item we are drawing in */
  2880.                 GetDialogItem ( dlg, kFinalRendrSep1, &iKind, &iHandle, &iRect) ;
  2881.                 FrameRect(&iRect ) ;
  2882.                 GetDialogItem ( dlg, kFinalRendrSep2, &iKind, &iHandle, &iRect) ;
  2883.                 FrameRect(&iRect ) ;
  2884.                 GetDialogItem ( dlg, kFinalRendrSep3, &iKind, &iHandle, &iRect) ;
  2885.                 FrameRect(&iRect ) ;
  2886.                 PenPat( &qd.black ) ;        
  2887.                 /*
  2888.                  * enable or disable the OK button depending on whether 
  2889.                  * we made a selection yet
  2890.                  */
  2891.                 GetDialogItem(  dlg, ok, &iKind, &iHandle, &iRect) ;
  2892.                 
  2893.                 retVal = false;
  2894.                 break ;
  2895.     
  2896.             default:
  2897.                 retVal = false;
  2898.                 break ;
  2899.         }
  2900.     }
  2901.     
  2902.     return retVal ;
  2903. }
  2904.  
  2905. /*------------------------------------------------------------ */
  2906.  
  2907. /*
  2908.  * IdleProgress method, handles setup, drawing and teardown for
  2909.  * the renderer progress dialog 
  2910.  */
  2911.  
  2912. TQ3Status MyViewIdleProgressMethod(
  2913.     TQ3ViewObject        view,
  2914.     const void            *idlerData,        /* contains the dialog ref */
  2915.     unsigned long        current,
  2916.     unsigned long        completed)
  2917. {
  2918.  
  2919.     /* 
  2920.      * Return kQ3Failure to cancel rendering, kQ3Success to continue. Don't
  2921.       * bother posting an error.
  2922.       */
  2923.       
  2924.     TQ3Status                    retVal = kQ3Success ;
  2925.     DialogPtr                    theDialog = (DialogPtr)idlerData ;
  2926.     ProgressBarDlogInfoHdl        theInfo ;
  2927.     CGrafPtr                    savedPort ;
  2928.     GDHandle                    savedGDH ;
  2929.     EventRecord                    theEvent ;
  2930.     char                        theKey ;
  2931.     
  2932.     /*
  2933.      *    Q3View_SetIdleMethod registers a callback that can be called
  2934.      *    by the system during rendering.  Unfortunately there is no way yet
  2935.      *    to set timer intervals when you want to be called.  Basically, it is
  2936.      *    up to the application's idler callback to check clocks to see if you
  2937.      *    were called back only a millisecond ago or an hour ago!
  2938.      *
  2939.      *    Q3View_SetIdleProgressMethod registers a callback that also gives
  2940.      *    progress information. This information is supplied by the renderer, and
  2941.      *    may or may not be based on real time.
  2942.      *
  2943.      *    If a renderer doesn't support the progress method, your method will be
  2944.      *    called with current == 0 and completed == 0.
  2945.      *    
  2946.      *    Otherwise, you are GUARANTEED to get called at least 2 or more times:
  2947.      *    
  2948.      *    ONCE            idleMethod(view, 0, n)        -> Initialize, Show Dialog
  2949.      *    zero or more    idleMethod(view, 1..n-1, n) -> Update progress
  2950.      *    ONCE            idleMethod(view, n, n)        -> Exit, Hide Dialog
  2951.      *    
  2952.      *    "current" is guaranteed to be less than or equal to "completed"
  2953.      *    "completed" may change values, but current/complete always indicates
  2954.      *    the degree of completion.
  2955.      *
  2956.      *    The calling conventions aid in managing any data associated with a 
  2957.      *    progress user interface indicator.
  2958.      */
  2959.     if( current == 0 && completed == 0 )
  2960.     {
  2961.         /* renderer doesn't support progress info, so just return success */
  2962.         retVal = kQ3Success ;
  2963.     }
  2964.     else
  2965.     {
  2966.         if( current == 0 )
  2967.         {
  2968.             /*
  2969.              * make a new progress bar dlog struct - we wait til here because 
  2970.              * prior to this point we have no idea what the max and min values
  2971.              * are for the dialog.
  2972.              */
  2973.             theInfo = PB_New( theDialog, kProgressBarPBItemID, completed, current ) ;
  2974.             
  2975.             /* the theInfo rec in the refCon field of the dialog */
  2976.             SetWRefCon((WindowPtr)theDialog, (long)theInfo);
  2977.             
  2978.             GetGWorld( &savedPort, &savedGDH ) ;
  2979.             SetGWorld( (CGrafPtr)theDialog, NULL ) ;
  2980.             
  2981.             /* make the hidden dialog visible */
  2982.             ShowWindow( theDialog ) ; 
  2983.             
  2984.             /* select it */
  2985.             SelectWindow( theDialog ) ;
  2986.             
  2987.             /* draw the dialog */
  2988.             UpdateDialog( theDialog, theDialog->visRgn ) ;
  2989.             
  2990.             SetGWorld( savedPort, savedGDH ) ;
  2991.             
  2992.         }
  2993.         else if( current == completed )
  2994.         {            
  2995.             GetGWorld( &savedPort, &savedGDH ) ;
  2996.             SetGWorld( (CGrafPtr)theDialog, NULL ) ;
  2997.             
  2998.             /* draw the last part of the progress bar */
  2999.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3000.             (**theInfo).thePBCurrValue = current ;
  3001.             
  3002.             /* update the progress bar */
  3003.             PB_Update( theInfo ) ;
  3004.             
  3005.             SetGWorld( savedPort, savedGDH ) ;
  3006.  
  3007.             /* tear down the progressbar dialog struct */
  3008.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3009.             DisposeHandle( (Handle)theInfo ) ;
  3010.             HideWindow( theDialog ) ;
  3011.         }
  3012.         else
  3013.         {            
  3014.             /* update the progress bar */
  3015.             GetGWorld( &savedPort, &savedGDH ) ;
  3016.             SetGWorld( (CGrafPtr)theDialog, NULL ) ;
  3017.  
  3018.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3019.             (**theInfo).thePBCurrValue = current ;
  3020.             
  3021.             /* update the progress bar */
  3022.             InvalRect( &theDialog->portRect ) ;
  3023.             DrawDialog( theDialog ) ;
  3024.             PB_Update( theInfo ) ;
  3025.             
  3026.             SetGWorld( savedPort, savedGDH ) ;
  3027.             
  3028.         }
  3029.     }
  3030.     
  3031.     /* 
  3032.      * last thing... check the event queue to see if there is a keydown event,
  3033.      * we want to see if the user hit command period to cancel.  Be warned - this 
  3034.      * way of doing this will flush keyevents from the event queue.
  3035.      */
  3036.      
  3037.     if( GetOSEvent( (keyDownMask | autoKeyMask), &theEvent) == true )
  3038.     {
  3039.         /* examine the event to see if its a command period */
  3040.         theKey = theEvent.message & charCodeMask;
  3041.         if( (theEvent.modifiers & cmdKey) && theKey == '.')
  3042.         {
  3043.             /* 
  3044.              * we want to cancel, we can signal this by returning kQ3Failure
  3045.              * before leaving this function, clean up & hide the progress dialog
  3046.              */
  3047.              
  3048.             /* tear down the progressbar dialog struct */
  3049.             theInfo = (ProgressBarDlogInfoHdl)GetWRefCon((WindowPtr)theDialog) ;
  3050.             DisposeHandle( (Handle)theInfo ) ;
  3051.             HideWindow( theDialog ) ;
  3052.  
  3053.             SysBeep(10) ;
  3054.             retVal = kQ3Failure ;
  3055.         }
  3056.         
  3057.     }
  3058.     return retVal ;
  3059. }
  3060.  
  3061.  
  3062. /*------------------------------------------------------------ */
  3063.  
  3064. /*
  3065.  * The user chose to render with a non interactive renderer, put
  3066.  * up a dialog to allow them to select and configure the renderer
  3067.  * and copy the appropriate values from the current viewer window.
  3068.  * 
  3069.  * this seems like a long winded way to do this.  We create a viewer
  3070.  * use that to image (which will take advantage of the renderers updates
  3071.  * get the pict for the viewer, image that into the offscreen for the window.
  3072.  */
  3073.  
  3074.  
  3075. void HandleViewFinalRendererOption( void ) 
  3076. {
  3077.     WindowPtr            theFrontWindow ;
  3078.     short                itemHit ;
  3079.     GrafPtr                savedPort ;
  3080.     popupPrivateData    **myPopupPrivateDataPtr ;
  3081.     
  3082.     short                iKind;
  3083.     Handle                iHandle;
  3084.     Rect                iRect;
  3085.     
  3086.     MenuHandle            thePopupMenuHdl ;
  3087.     unsigned char        rendererName[255] ;
  3088.     TQ3RendererObject    theRenderer ;
  3089.     unsigned char        numText[255] ;
  3090.     
  3091.     OSErr                 theErr ;
  3092.     
  3093.     long                width ;
  3094.     long                height ;
  3095.     long                theControlValue = 0;
  3096.  
  3097.     /* 
  3098.      * the final renderer option should only be available for a 
  3099.      * viewer window, so we can assume the the front window at the 
  3100.      * time this is called is a viewer
  3101.      */
  3102.     theFrontWindow = FrontWindow() ;
  3103.  
  3104.     GetPort( &savedPort ) ;
  3105.     SetPort( (GrafPtr)gFinalRenderDialog ) ;
  3106.     InvalRect( &((GrafPtr)gFinalRenderDialog)->portRect) ;
  3107.  
  3108.     SetDialogDefaultItem(gFinalRenderDialog, kStdOkItemIndex) ;
  3109.  
  3110.     ShowWindow( (WindowPtr)gFinalRenderDialog ) ;
  3111.     SelectWindow( (WindowPtr)gFinalRenderDialog ) ;
  3112.     
  3113.     do {
  3114.         ModalDialog( gModalFilterProcUPP, &itemHit ) ;
  3115.         
  3116.         if( itemHit == kFinalRendrPopup ) {
  3117.         
  3118.             /* the user choose the popup.  The item number selected will be the control value
  3119.              * we need to get the menuhandle associated with the control, it is in the private
  3120.              * control data field, as documented in Inside Macintosh: Toolbox page 5-77
  3121.              */
  3122.             
  3123.             /* get the control handle for the popup    */        
  3124.             GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  3125.             
  3126.             /* extract from the control the menuhandle */
  3127.             myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  3128.             thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ;
  3129.     
  3130.             /* get the string associated with the users selection */
  3131.             HLock((Handle)iHandle) ;
  3132.             theControlValue = GetControlValue((ControlHandle)iHandle) ;
  3133.  
  3134.             GetMenuItemText ( thePopupMenuHdl, theControlValue, rendererName );
  3135.             HUnlock((Handle)iHandle) ;
  3136.                         
  3137.             /* reset itemHit to something else */
  3138.             itemHit = 0 ;
  3139.         
  3140.         }
  3141.         else if( itemHit == kFinalRendrConfigure ) {
  3142.             
  3143.             /* get the control handle for the popup    */        
  3144.             GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  3145.             
  3146.             /* extract from the control the menuhandle */
  3147.             myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  3148.             thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ;
  3149.     
  3150.             /* get the string associated with the users selection */
  3151.             HLock((Handle)iHandle) ;
  3152.             theControlValue = GetControlValue((ControlHandle)iHandle) ;
  3153.                         
  3154.             if( theControlValue != 0 )
  3155.             {
  3156.                 theRenderer = GetRendererByType( pNonInteractiveTypes[theControlValue-1] ) ;
  3157.                 
  3158.                 if( theRenderer != NULL && Q3Renderer_HasModalConfigure( theRenderer )) 
  3159.                 {
  3160.                     TQ3DialogAnchor         qd3dAnchor ;
  3161.                     TQ3Boolean                qd3dCanceled ;
  3162.                     TQ3Status                theStatus ;
  3163.                     
  3164.                     
  3165.                     /* the renderer prefs dialog will be modal */
  3166.                     qd3dAnchor.clientEventHandler = NULL ;
  3167.                     theStatus = Q3Renderer_ModalConfigure(
  3168.                                             theRenderer,
  3169.                                             qd3dAnchor,
  3170.                                             &qd3dCanceled) ;
  3171.                                             
  3172.                 }
  3173.             }
  3174.             else
  3175.                 SysBeep(10) ;
  3176.         }
  3177.     } while( itemHit != kStdCancelItemIndex && itemHit != kStdOkItemIndex ) ;
  3178.     
  3179.     /* we're done with the dialog window, hide it 'till next time */
  3180.     HideWindow( (WindowPtr)gFinalRenderDialog ) ;
  3181.     
  3182.     /* check we didn't cancel */
  3183.     if( itemHit == kStdOkItemIndex )
  3184.     {
  3185.         TQ3ViewerObject        tempViewer ;
  3186.         WindowPtr            finalImageWin ;
  3187.         PicHandle            theImage ;
  3188.  
  3189.         /* get the control handle for the popup    */        
  3190.         GetDialogItem ( gFinalRenderDialog, kFinalRendrPopup, &iKind, &iHandle, &iRect) ;
  3191.         
  3192.         /* extract from the control the menuhandle */
  3193.         myPopupPrivateDataPtr = (popupPrivateData **)(**(ControlHandle)iHandle).contrlData ; 
  3194.         thePopupMenuHdl = (**myPopupPrivateDataPtr).mHandle ;
  3195.  
  3196.         /* get the string associated with the users selection */
  3197.         HLock((Handle)iHandle) ;
  3198.         theControlValue = GetControlValue((ControlHandle)iHandle) ;
  3199.  
  3200.         GetMenuItemText ( thePopupMenuHdl, theControlValue, rendererName );
  3201.         HUnlock((Handle)iHandle) ;
  3202.                     
  3203.         /* reset itemHit to something else */
  3204.         itemHit = 0 ;
  3205.         
  3206.         /* get the window size - we can get the dialog item string and just StringToNum it
  3207.          * since our filter proc filders out all key stroked except digits
  3208.          */
  3209.         GetDialogItem ( gFinalRenderDialog, kFinalRendrHeight, &iKind, &iHandle, &iRect) ;
  3210.         GetDialogItemText ( iHandle, numText ) ;
  3211.         StringToNum ( numText, &height ) ;
  3212.         
  3213.         GetDialogItem ( gFinalRenderDialog, kFinalRendrWidth, &iKind, &iHandle, &iRect) ;
  3214.         GetDialogItemText ( iHandle, numText ) ;
  3215.         StringToNum ( numText, &width ) ;
  3216.                 
  3217.         /* make a new window with the renderer name of the correct size */
  3218.         finalImageWin = DoCreateNewPictWindow( rendererName, width, height ) ;
  3219.         
  3220.         /* make a viewer for this window with no controller */
  3221.         if( finalImageWin != NULL ) 
  3222.         {
  3223.             /* get these from the original viewer referenced by FrontWindow */
  3224.             TQ3GroupObject        savedGroup ;
  3225.             TQ3CameraObject        savedCamera ;
  3226.             TQ3GroupObject        savedLights ;
  3227.             TQ3ColorARGB        savedBGColor ;
  3228.             
  3229.             TQ3ViewerObject        originalViewer ;
  3230.             TQ3ViewObject        originalView ;
  3231.             unsigned long        theViewerFlags ;
  3232.             GWorldPtr            theGWorld ; 
  3233.             
  3234.             CGrafPtr            savedPort ;
  3235.             GDHandle            savedGDH ;
  3236.  
  3237.             theGWorld = GetGWorldFromPictWindow( finalImageWin ) ;
  3238.             
  3239.             /* make a temp viewer to use to make the PICT */
  3240.             if( theGWorld != NULL 
  3241.                 && (tempViewer = Q3ViewerNew( (CGrafPtr)theGWorld, 
  3242.                                 &theGWorld->portRect, 
  3243.                                 kQ3ViewerDefault )) != NULL)
  3244.             {
  3245.                 
  3246.                 /* lock the viewer's GWorld for updates */
  3247.                 LockPixels(GetGWorldPixMap(theGWorld)) ;
  3248.  
  3249.                 GetGWorld( &savedPort, &savedGDH ) ;
  3250.                 SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  3251.  
  3252.                 originalViewer = GetViewerFromViewerWindow( theFrontWindow ) ;
  3253.  
  3254.                 if( originalViewer != NULL ) 
  3255.                 {
  3256.                     TQ3ViewObject        newView ;
  3257.                     
  3258.                     /* set the group up, copy from original viewer */
  3259.                     savedGroup = Q3ViewerGetGroup( originalViewer ) ;
  3260.                     if( savedGroup != NULL )
  3261.                     {
  3262.                         Q3ViewerUseGroup( tempViewer, savedGroup) ;
  3263.                         Q3Object_Dispose( savedGroup ) ;
  3264.                     }
  3265.                     
  3266.                     /* copy the camera from the original viewer */
  3267.                     originalView = Q3ViewerGetView( originalViewer ) ;
  3268.                     newView = Q3ViewerGetView( tempViewer ) ;
  3269.                     
  3270.                     if( originalView != NULL )
  3271.                     {
  3272.                         Q3View_GetCamera( originalView, &savedCamera );
  3273.                         if( savedCamera != NULL )
  3274.                         {
  3275.                             Q3View_SetCamera( newView, savedCamera );
  3276.                             Q3Object_Dispose( savedCamera ) ;
  3277.                         }
  3278.                     }
  3279.                     
  3280.                     /* copy the light group from the original viewer */
  3281.                     if( originalView != NULL )
  3282.                     {
  3283.                         Q3View_GetLightGroup( originalView, &savedLights );
  3284.                         if( savedCamera != NULL )
  3285.                         {
  3286.                             Q3View_SetLightGroup( newView, savedLights );
  3287.                             Q3Object_Dispose( savedLights ) ;
  3288.                         }
  3289.                     }
  3290.  
  3291.                     /* copy the background color from the original viewer */
  3292.                     if( originalView != NULL )
  3293.                     {
  3294.                         Q3ViewerGetBackgroundColor( originalViewer, &savedBGColor ) ;
  3295.                         if( savedCamera != NULL )
  3296.                         {
  3297.                             Q3ViewerSetBackgroundColor( tempViewer, &savedBGColor ) ;
  3298.                         }
  3299.                     }
  3300.                     
  3301.                     /*
  3302.                      * we don't need to dispose the view, since viewergetview doesn't
  3303.                      * increment the reference counts of the viewer.
  3304.                      */
  3305.                     
  3306.                     theViewerFlags = Q3ViewerGetFlags( tempViewer ) ;
  3307.                     
  3308.                     theViewerFlags = theViewerFlags &~ kQ3ViewerControllerVisible;
  3309.                     theViewerFlags = theViewerFlags &~ kQ3ViewerDrawFrame;
  3310.                     theViewerFlags = theViewerFlags &~ kQ3ViewerDrawDragBorder;
  3311.                     
  3312.                     Q3ViewerSetFlags( tempViewer, theViewerFlags ) ;
  3313.                     
  3314.                     /* this is a little funky - we are using a modeless dialog to display the
  3315.                      * progress of the render, but the main event loop will never get called,
  3316.                      * since the dialog is only "called back" from the render.
  3317.                      */
  3318.                                      
  3319.                     if( gProgressModelessDialog != NULL )
  3320.                     {
  3321.                         /* install the callback */
  3322.                         Q3View_SetIdleProgressMethod( 
  3323.                                 newView, 
  3324.                                 MyViewIdleProgressMethod,
  3325.                                 (const void *)gProgressModelessDialog ) ;
  3326.                     
  3327.                     }
  3328.                     
  3329.                     /* image the document */
  3330.  
  3331.                     /* set the renderer to the renderer from the popup for this document */
  3332.                     ViewerSetRenderer( pNonInteractiveTypes[theControlValue-1], tempViewer ) ;
  3333.                     Q3ViewerDraw( tempViewer ) ;
  3334.                     
  3335.                     /* dispose of the viewer object */
  3336.                     Q3ViewerDispose( tempViewer ) ;
  3337.                     
  3338.                     /*
  3339.                      * it is possible that if the renderer does not follow the calling conventions
  3340.                      * to update the progress dialog, that that dialog can be lest on the screen
  3341.                      * so check the fron window, if it is the progress dialog then hide it
  3342.                      */
  3343.                     if( FrontWindow() == gProgressModelessDialog )
  3344.                         HideWindow( gProgressModelessDialog ) ;
  3345.                 }
  3346.                 
  3347.                 SetGWorld( savedPort, savedGDH ) ;
  3348.                 
  3349.                 /* lock the viewer's GWorld for updates */
  3350.                 UnlockPixels(GetGWorldPixMap(theGWorld)) ;
  3351.  
  3352.             }
  3353.         }
  3354.     }
  3355.     else
  3356.     {
  3357.         SelectWindow( theFrontWindow ) ;
  3358.         SetPort( savedPort ) ;
  3359.     }    
  3360. }
  3361.  
  3362. /*------------------------------------------------------------ */
  3363.  
  3364. /*
  3365.  * handle menu commands in the view menu
  3366.  */
  3367.  
  3368.  
  3369. void HandleViewMenu( short menuItem )
  3370. {
  3371.     DocumentHdl            theDocumentHdl ;
  3372.     ViewerDataHdl        theViewerHdl ;
  3373.     WindowPtr            theWindow ;
  3374.     TQ3ViewerObject        theViewer ;
  3375.  
  3376.     unsigned long        theViewerFlags;
  3377.     Rect                theTmpRect ;
  3378.     GrafPtr                savedPort ;
  3379.     RGBColor            theRGBColor ;
  3380.     TQ3ColorARGB        theViewerBGColor;
  3381.  
  3382.     theWindow = FrontWindow() ;
  3383.     
  3384.     if( theWindow != NULL )
  3385.     {
  3386.         /*
  3387.          * get the reference to our viewer document data structure
  3388.          * from the long reference constant for the window.  Cast
  3389.          * it to the appropriate type.  If we can't get it (i.e. it's
  3390.          * null we want to bail
  3391.          */
  3392.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3393.         if(theDocumentHdl == NULL) 
  3394.             return ;
  3395.         
  3396.         /* get the reference to the viewer object from our data structure  */    
  3397.         if((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) == NULL)
  3398.             return ;
  3399.             
  3400.         /* get the reference to the viewer object from our data structure  */    
  3401.         theViewer = (**theViewerHdl).fViewer ;
  3402.         if(theViewer == NULL) 
  3403.             return ;
  3404.         
  3405.         /*
  3406.          * since most of the items in this menu rely on adjusting
  3407.          * the viewer flags, we'll get the flags here so we can
  3408.          * bitwise manipulate them in the switch below
  3409.          */ 
  3410.         theViewerFlags = Q3ViewerGetFlags( theViewer ) ;
  3411.     
  3412.         switch ( menuItem ) 
  3413.         {
  3414.             case iViewFinalRendererItem:
  3415.             
  3416.                 HandleViewFinalRendererOption() ;
  3417.                 break ;
  3418.  
  3419.             /*
  3420.              * the renderer item in this menu is handled
  3421.              * by handlers for it's respective hierarchical        
  3422.              * menus, so we just need to handle the ones below
  3423.              */    
  3424.             
  3425.             case iViewBadgeItem:
  3426.                 /* 
  3427.                  * this toggles the viewer bage and hides the
  3428.                  * vcontroller, clicking in the badge will
  3429.                  * hide the badge and show the controller
  3430.                  */
  3431.                 theViewerFlags ^= kQ3ViewerShowBadge;
  3432.                 theViewerFlags ^= kQ3ViewerControllerVisible;
  3433.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3434.                 break ;
  3435.                 
  3436.             case iViewCameraButtonItem:
  3437.                 theViewerFlags ^= kQ3ViewerButtonCamera ;
  3438.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3439.                 break ;
  3440.                 
  3441.             case iViewTruckButtonItem:
  3442.                 theViewerFlags ^= kQ3ViewerButtonTruck ;
  3443.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3444.                 break ;
  3445.                 
  3446.             case iViewOrbitButtonItem:
  3447.                 theViewerFlags ^= kQ3ViewerButtonOrbit ;
  3448.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3449.                 break ;
  3450.                 
  3451.             case iViewZoomButtonItem:
  3452.                 theViewerFlags ^= kQ3ViewerButtonZoom ;
  3453.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3454.                 break ;
  3455.                 
  3456.             case iViewDollyButtonItem:
  3457.                 theViewerFlags ^= kQ3ViewerButtonDolly ;
  3458.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3459.                 break ;
  3460.                 
  3461.             case iViewInsetNFrameItem:
  3462.                 /*
  3463.                  * this toggles drawing the viewer slightly smaller 
  3464.                  *than the window.  We key off the kQ3ViewerDrawFrame
  3465.                  * viewer flag - if it is set then we are already inset
  3466.                  */
  3467.                 theTmpRect = theWindow->portRect ;
  3468.                 if( theViewerFlags & kQ3ViewerDrawFrame ) 
  3469.                 {
  3470.                     Q3ViewerSetBounds( theViewer, &theTmpRect ) ;
  3471.                 }
  3472.                 else
  3473.                 {
  3474.                     InsetRect( &theTmpRect, kInsetPixelsConst, kInsetPixelsConst ) ;
  3475.                     Q3ViewerSetBounds( theViewer, &theTmpRect ) ;
  3476.                 }
  3477.                 theViewerFlags ^= kQ3ViewerDrawFrame ;
  3478.                 Q3ViewerSetFlags( theViewer, theViewerFlags ) ;
  3479.                 
  3480.                 GetPort( &savedPort ) ;
  3481.                 SetPort( (GrafPtr)theWindow ) ;
  3482.                 EraseRect( &theWindow->portRect ) ;
  3483.                 SetPort( savedPort ) ;
  3484.                 
  3485.                 break ;
  3486.             
  3487.             case iViewSetBackgroundColorItem:
  3488.     
  3489.                 Q3ViewerGetBackgroundColor(theViewer, &theViewerBGColor);
  3490.                 theRGBColor.red = theViewerBGColor.r * 65535.0;
  3491.                 theRGBColor.green = theViewerBGColor.g * 65535.0;
  3492.                 theRGBColor.blue = theViewerBGColor.b * 65535.0;
  3493.                 
  3494.                 if(BackgroundColor( &theRGBColor, "\pPick a viewer background color:" ))
  3495.                 {
  3496.                     theViewerBGColor.a = 1;
  3497.                     theViewerBGColor.r = theRGBColor.red / 65535.0;
  3498.                     theViewerBGColor.g = theRGBColor.green / 65535.0;
  3499.                     theViewerBGColor.b = theRGBColor.blue / 65535.0;
  3500.                     Q3ViewerSetBackgroundColor(theViewer, &theViewerBGColor);
  3501.                 }
  3502.                 break;                                
  3503.         }
  3504.     }
  3505.     
  3506.     GetPort( &savedPort ) ;
  3507.     SetPort( (GrafPtr)theWindow ) ;
  3508.     InvalRect( &theWindow->portRect ) ;
  3509.     SetPort( savedPort ) ;
  3510. }
  3511.  
  3512. Boolean BackgroundColor(RGBColor *theRGBColor, unsigned char *thePrompt )
  3513. {
  3514.     ColorPickerInfo        cpInfo;
  3515.     Boolean                returnValue = false ;
  3516.     
  3517.     /* setting input color to be an RGB color  */
  3518.     cpInfo.theColor.color.rgb.red = (*theRGBColor).red;
  3519.     cpInfo.theColor.color.rgb.blue = (*theRGBColor).blue;
  3520.     cpInfo.theColor.color.rgb.green = (*theRGBColor).green;
  3521.     
  3522.     cpInfo.theColor.profile = 0L;
  3523.     
  3524.     /* no colorsync destination profile  */
  3525.     cpInfo.dstProfile = 0L;
  3526.     
  3527.     /* set the color picker flags  */
  3528.     cpInfo.flags = kColorPickerAppIsColorSyncAware | kColorPickerCanModifyPalette | 
  3529.                         kColorPickerCanAnimatePalette;
  3530.                         
  3531.     /* center dialog box on the deepest color screen  */
  3532.     cpInfo.placeWhere = kDeepestColorScreen;
  3533.     
  3534.     /* use the system default picker  */
  3535.     cpInfo.pickerType = 0L;
  3536.     
  3537.     /* install event filter and color-changed functions  */
  3538.     cpInfo.eventProc = nil;            
  3539.     cpInfo.colorProc = nil;
  3540.     cpInfo.colorProcData = 0L;
  3541.     
  3542.     /* sanity check  */
  3543.     if( thePrompt[ 0 ] >= 255 )
  3544.         thePrompt[ 0 ] = 255 ;
  3545.         
  3546.     BlockMove( thePrompt, cpInfo.prompt, thePrompt[0] ) ;
  3547.     
  3548.     /* describe the Edit menu for Color Picker Manager  */
  3549.     cpInfo.mInfo.editMenuID = mEditMenu ;
  3550.     cpInfo.mInfo.cutItem     = iEditCutItem;
  3551.     cpInfo.mInfo.copyItem     = iEditCopyItem;
  3552.     cpInfo.mInfo.pasteItem    = iEditPasteItem;
  3553.     cpInfo.mInfo.clearItem     = iEditClearItem;
  3554.     cpInfo.mInfo.undoItem     = iEditUndoItem;
  3555.  
  3556.     /* display dialog box to allow user to choose a color  */
  3557.     if(PickColor(&cpInfo) == noErr && cpInfo.newColorChosen)
  3558.     {
  3559.         /* use this new color  */
  3560.         (*theRGBColor).red = cpInfo.theColor.color.rgb.red ;
  3561.         (*theRGBColor).blue = cpInfo.theColor.color.rgb.blue ;
  3562.         (*theRGBColor).green = cpInfo.theColor.color.rgb.green ;
  3563.         
  3564.         /* set up the return value  */
  3565.         returnValue = cpInfo.newColorChosen ;
  3566.     }
  3567.         
  3568.     return returnValue ;
  3569. }
  3570.  
  3571. /*------------------------------------------------------------ */
  3572.  
  3573. /*
  3574.  * make sure that menus are enabled and disabled in an
  3575.  * appropriate manner
  3576.  */
  3577.  
  3578.  
  3579. void AdjustMenus( void ) 
  3580. {
  3581.     MenuHandle            theMenu ;
  3582.     DocumentHdl            theDocumentHdl ;
  3583.     WindowPtr            theWindow ;
  3584.     TQ3ViewerObject        theViewer ;
  3585.     TQ3ViewObject         myView ;
  3586.     TQ3Status            myStatus ;
  3587.     TQ3RendererObject    myRenderer ;
  3588.     TQ3ObjectType        theRendererType ;
  3589.     long                tmpLong, theScrapOffset ;
  3590.     unsigned long        theViewerFlags;
  3591.     unsigned long        theViewerState ;
  3592.     AdjustMenusProc        myAdjustMenus ;
  3593.     char                itemString[255] ;
  3594.     unsigned long        itemStringLength ;
  3595.  
  3596.     theWindow = FrontWindow() ;
  3597.     
  3598.     /* do we have a viewer window open  */
  3599.     if( theWindow != NULL ) {
  3600.         /*
  3601.          * get the reference to our viewer document data structure
  3602.          * from the long reference constant for the window.  Cast
  3603.          * it to the appropriate type.  If we can't get it (i.e. it's
  3604.          * null we want to bail
  3605.          */
  3606.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3607.         if(theDocumentHdl == NULL) 
  3608.             return ;
  3609.             
  3610.         myAdjustMenus = (**theDocumentHdl).procs->adjustMenusP ;
  3611.         
  3612.         if( myAdjustMenus != NULL )
  3613.             (*myAdjustMenus)(theWindow) ;
  3614.     }
  3615.     else {
  3616.     
  3617.         /* there is NOT a front window, set defaults for menu commands */
  3618.     
  3619.         /* adjust the file menu */
  3620.         theMenu = GetMenuHandle ( mFileMenu ) ;
  3621.         
  3622.         EnableItem ( theMenu, iFileNewItem );        /* always enabled */
  3623.         EnableItem ( theMenu, iFileOpenItem );        /* always enabled */
  3624.         EnableItem ( theMenu, iFileQuitItem );        /* always enabled */
  3625.  
  3626.         DisableItem ( theMenu, iFileCloseItem );
  3627.         DisableItem ( theMenu, iFileSaveItem );
  3628.         DisableItem ( theMenu, iFileSaveAsItem );
  3629.         DisableItem ( theMenu, iFileRevertItem );
  3630.         DisableItem ( theMenu, iFilePageSetupItem );
  3631.         DisableItem ( theMenu, iFilePrintItem );
  3632.  
  3633.         /* adjust the edit menu */
  3634.         theMenu = GetMenuHandle ( mEditMenu ) ;
  3635.         DisableItem ( theMenu, 0L );
  3636.         
  3637.         /* disable the entire view menu if there is no window */
  3638.         theMenu = GetMenuHandle ( mViewMenu ) ;
  3639.         DisableItem ( theMenu, 0L );
  3640.  
  3641.     }
  3642.     DrawMenuBar() ;
  3643. }
  3644.  
  3645. /*------------------------------------------------------------  */
  3646.  
  3647. /* Determining the 3D Viewer version 
  3648.  *
  3649.  * Version 1.5 of the 3D viewer adds some new APIs and new features. 
  3650.  * In order for an application to determine at runtime that the version 
  3651.  * 1.5 functionality of the 3D viewer is available an application must 
  3652.  * check the version of the viewer. Unfortunately prior to version 1.5 
  3653.  * the 3D viewer did not have a gestalt or an API call to get its version. 
  3654.  * Version 1.5 of the viewer adds a call Q3ViewerGetVersion. But an 
  3655.  * application will want to first check that the Q3ViewerGetVersion 
  3656.  * symbol is resolved before calling the Q3ViewerGetVersion function 
  3657.  * on the chance the user has an older version of viewer shared library 
  3658.  * installed. An application which depends on the newer functionality 
  3659.  * will then need to take appropriate action such as displaying an alert 
  3660.  * or disabling specific features.
  3661.  */
  3662.  
  3663. OSErr GetViewerVersion( unsigned long *major, unsigned long *minor ) 
  3664.     
  3665.     /*
  3666.      * version 1.0 of the QuickDraw 3D viewer did not 
  3667.      * have a get version call, so check to see if the 
  3668.      * symbol for the API routine descriptor is loaded
  3669.      */ 
  3670.     if((Boolean)Q3ViewerGetVersion == kUnresolvedCFragSymbolAddress) 
  3671.     {
  3672.         *major = 1; 
  3673.         *minor = 0; 
  3674.         return noErr; 
  3675.     } 
  3676.     else 
  3677.     { 
  3678.         return Q3ViewerGetVersion(major, minor); 
  3679.     } 
  3680. }
  3681.  
  3682.  
  3683. /*------------------------------------------------------------  */
  3684.  
  3685. /*
  3686.  *     DoDrawGrowIcon 
  3687.  *  
  3688.  *     Draw the grow icon. We do this in such a way that the scrollbar lines are 
  3689.  *     not drawn. Normally, when the Toolbox routine DrawGrowIcon is called, 
  3690.  *     vertical and horizontal lines are also drawn indicating where the 
  3691.  *     scrollbars will be drawn. We don’t have scrollbars, so we don’t want those 
  3692.  *     lines drawn. We avoid them by setting the clipping region of the window to 
  3693.  *     include the grow box only. We then call DrawGrowIcon, and restore the old 
  3694.  *     clipping region before returning.
  3695.  *
  3696.  *    Make sure that this gets called after the control strip for
  3697.  *    a window is drawn. 
  3698.  */
  3699.  
  3700. void    DoDrawGrowIcon(WindowPtr theWindow)
  3701. {
  3702.     Rect        iconRect;
  3703.     RgnHandle    oldClip;
  3704.     
  3705.  
  3706.     SetPort(theWindow);
  3707.     oldClip = NewRgn();
  3708.     GetClip(oldClip);
  3709.  
  3710.     iconRect = theWindow->portRect;
  3711.     iconRect.top = iconRect.bottom - 15;
  3712.     iconRect.left = iconRect.right - 15;
  3713.     ClipRect(&iconRect);
  3714.  
  3715.     PenNormal();
  3716.     DrawGrowIcon(theWindow);
  3717.  
  3718.     SetClip(oldClip);
  3719.     DisposeRgn(oldClip);
  3720. }
  3721.  
  3722.  
  3723. /*------------------------------------------------------------ */
  3724.  
  3725. /*
  3726.  * create a new viewer document window, this includes creating a
  3727.  * document record, a window and an associated viewer object.  the
  3728.  * document record is stored in the window's refcon field, so it
  3729.  * can be accessed as required via the window record.
  3730.  */
  3731.  
  3732. WindowPtr DoCreateNewViewerWindow( unsigned char *windowName )
  3733. {
  3734.     WindowPtr            theWindow ;
  3735.     Rect                myRect = { 0, 0, kWindHeight, kWindWidth } ;
  3736.     TQ3ViewerObject        myViewer ;
  3737.     DocumentHdl            myViewerDocument = NULL ;
  3738.     
  3739.     /* create a document record to hold the  */
  3740.     /* data for this instance  */
  3741.     if((myViewerDocument = (DocumentHdl)NewHandleClear(sizeof(Document))) == NULL)
  3742.         return NULL ;
  3743.     
  3744.     
  3745.     /* ideally we should stagger the rect  */
  3746.     OffsetRect( &myRect, 50, 50 ) ; 
  3747.                       
  3748.     theWindow = NewCWindow( NULL, 
  3749.                          &myRect, 
  3750.                          windowName, 
  3751.                          true, 
  3752.                          documentProc, 
  3753.                          (WindowPtr)-1, 
  3754.                          true, 
  3755.                          0L ) ;
  3756.                          
  3757.     /* create the viewer object associated with this window  */                   
  3758.     if((myViewer = Q3ViewerNew( (CGrafPtr)theWindow, 
  3759.                                 &theWindow->portRect, 
  3760.                                 kQ3ViewerDefault )) != NULL) 
  3761.     {
  3762.         ViewerDataHdl        myViewerData = (ViewerDataHdl)NewHandleClear(sizeof(ViewerData)) ;
  3763.         if(myViewerData == NULL)
  3764.         {
  3765.             DisposeHandle( (Handle)myViewerDocument ) ;
  3766.             return NULL ;
  3767.         }
  3768.         
  3769.         /* put the magic cookie in the first field so we can identify this as a valid viewer */
  3770.         (**myViewerDocument).fDocumentMagic = kViewerMagic ;
  3771.         
  3772.         /* set up the procs field */
  3773.         (**myViewerDocument).procs = &viewerProcs ;
  3774.         
  3775.         /* set up the private data part of the document structure */
  3776.         (**myViewerData).fViewer = myViewer ;
  3777.         
  3778.         /* stuff the handle in the viewerdata field */
  3779.         (**myViewerDocument).fPrivate = (void *) myViewerData ;
  3780.         
  3781.         /* store a reference to the document structure in the refcon
  3782.          * field of the window  
  3783.          */
  3784.         SetWRefCon( theWindow, (long)myViewerDocument ) ;
  3785.  
  3786.         /* finally create a new print record */
  3787.         DoCreatePrintRecord( myViewerDocument ) ;
  3788.  
  3789.     }
  3790.     else
  3791.     {
  3792.         /* clean up any allocates storage and quit  */
  3793.         if( myViewerDocument )
  3794.             DisposeHandle( (Handle)myViewerDocument ) ;
  3795.         
  3796.         if( theWindow ) 
  3797.             CloseWindow( theWindow ) ;
  3798.         
  3799.         theWindow = NULL ;
  3800.     }
  3801.     
  3802.     return theWindow ;
  3803. }
  3804.  
  3805. /*------------------------------------------------------------ */
  3806.  
  3807. /*
  3808.  * handles the New menu item in the file menu
  3809.  */
  3810.  
  3811.  
  3812. WindowPtr ViewerWindow_New( unsigned char *windowTitle )
  3813. {
  3814.     WindowPtr     theWindow ;    
  3815.     theWindow = DoCreateNewViewerWindow( windowTitle ) ;
  3816.     return theWindow ;
  3817. }
  3818.     
  3819. /*------------------------------------------------------------ */
  3820.  
  3821. /*
  3822.  * handles the Save As menu item in the file menu
  3823.  */
  3824.  
  3825.  
  3826. OSErr ViewerWindow_SaveAs( WindowPtr theWindow )
  3827. {
  3828.     OSErr                theError = paramErr ;
  3829.     short                theRef ;
  3830.  
  3831.     TQ3ViewerObject        theViewer ;
  3832.     StandardFileReply    theSFReply ;
  3833.     DocumentHdl            theDocumentHdl ;
  3834.  
  3835.  
  3836.     /* this option can't be selected unless there is a frontwindow  */
  3837.     /* the option is dimmed in adjustmenus if there is no window  */
  3838.     if( theWindow != NULL ) /* sanity check  */
  3839.     {
  3840.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3841.         if(theDocumentHdl != NULL
  3842.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic ) 
  3843.         {
  3844.             StandardPutFile("\pSave model as:", "\pUntitled", &theSFReply);
  3845.             if (theSFReply.sfGood)
  3846.             {
  3847.                 theError = FSpOpenDF(&theSFReply.sfFile, fsWrPerm, &theRef);
  3848.                 if (theError != noErr)
  3849.                 {
  3850.                     theError = FSpCreate(&theSFReply.sfFile, '????', '3DMF', theSFReply.sfScript);
  3851.                     if (theError == noErr)
  3852.                         theError = FSpOpenDF(&theSFReply.sfFile, fsCurPerm, &theRef);
  3853.                 }
  3854.                 if (theError == noErr)
  3855.                 {
  3856.                     /* get the viewer object from the document */
  3857.                     ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  3858.                     if( theViewerHdl != NULL )
  3859.                     {
  3860.                         HLock((Handle)theViewerHdl) ;
  3861.                         (**theViewerHdl).fFSSpec = theSFReply.sfFile ;
  3862.                         theViewer= (**theViewerHdl).fViewer ;
  3863.                         theError = Q3ViewerWriteFile(theViewer, (long)theRef);
  3864.                         theError = FSClose(theRef);
  3865.                         HUnlock((Handle)theViewerHdl) ;
  3866.                     }
  3867.                 }
  3868.                 
  3869.                 /* reset the window title  */
  3870.                 SetWTitle( theWindow, theSFReply.sfFile.name );
  3871.             }                    
  3872.         }
  3873.     }
  3874.     return theError ;
  3875. }
  3876.  
  3877. /*------------------------------------------------------------ */
  3878.  
  3879. /*
  3880.  * handles the Save menu item in the file menu
  3881.  */
  3882.  
  3883.  
  3884. OSErr ViewerWindow_Save( WindowPtr theWindow )
  3885. {
  3886.     OSErr                theError = paramErr ;
  3887.     short                theRef ;
  3888.  
  3889.     TQ3ViewerObject        theViewer ;
  3890.  
  3891.     DocumentHdl    theDocumentHdl ;
  3892.     FSSpec                theFSSpec ;
  3893.  
  3894.     /* this option can't be selected unless there is a frontwindow  */
  3895.     /* the option is dimmed in adjustmenus if there is no window  */
  3896.     if( theWindow != NULL )        /* sanity check  */
  3897.     {
  3898.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3899.         if(theDocumentHdl != NULL  
  3900.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  3901.         {
  3902.             /* get the viewer object from the document */
  3903.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  3904.             if( theViewerHdl != NULL )
  3905.             {
  3906.                 HLock((Handle)theViewerHdl) ;
  3907.                 theFSSpec = (**theViewerHdl).fFSSpec ;
  3908.                 /* open the file  */
  3909.                 theError = FSpOpenDF ( &theFSSpec, fsWrPerm, &theRef ) ;
  3910.                 if( theError == noErr ) 
  3911.                 {
  3912.                     if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  3913.                     {
  3914.                         theError = Q3ViewerWriteFile( theViewer, (long)theRef );
  3915.                         if( theError == noErr )
  3916.                             theError = FSClose ( theRef ) ;
  3917.                     }
  3918.                 }
  3919.                 HUnlock((Handle)theViewerHdl) ;
  3920.             }
  3921.         }
  3922.     }
  3923.     return theError ;
  3924.             
  3925. }
  3926.         
  3927. /*------------------------------------------------------------ */
  3928.  
  3929. /*
  3930.  * handles the Revert menu item in the file menu
  3931.  */
  3932.  
  3933.  
  3934. OSErr ViewerWindow_Revert( WindowPtr theWindow )
  3935. {
  3936.     OSErr                theError = paramErr ;
  3937.     short                theRef ;
  3938.     GrafPtr                savedPort ;
  3939.  
  3940.     TQ3ViewerObject        theViewer ;
  3941.  
  3942.     DocumentHdl    theDocumentHdl ;
  3943.     FSSpec                theFSSpec ;
  3944.  
  3945.     /* this option can't be selected unless there is a frontwindow  */
  3946.     /* the option is dimmed in adjustmenus if there is no window  */
  3947.     if( theWindow != NULL )        /* sanity check  */
  3948.     {
  3949.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  3950.         if(theDocumentHdl != NULL
  3951.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  3952.         {
  3953.             /* get the viewer object from the document */
  3954.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  3955.             if( theViewerHdl != NULL )
  3956.             {
  3957.                 HLock((Handle)theViewerHdl) ;
  3958.                 theFSSpec = (**theViewerHdl).fFSSpec ;
  3959.                 
  3960.                 /* open the file  */
  3961.                 theError = FSpOpenDF ( &theFSSpec, fsRdPerm, &theRef ) ;
  3962.                 if( theError == noErr ) 
  3963.                 {
  3964.                     if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  3965.                     {
  3966.                         theError = Q3ViewerUseFile( theViewer, (long)theRef );
  3967.                         if( theError == noErr )
  3968.                             theError = FSClose ( theRef ) ;
  3969.                     }
  3970.                 }
  3971.  
  3972.                 HUnlock((Handle)theViewerHdl) ;
  3973.             }
  3974.         }
  3975.     }
  3976.     GetPort( &savedPort ) ;
  3977.     SetPort( (GrafPtr)theWindow ) ;
  3978.     InvalRect( &theWindow->portRect ) ;
  3979.     SetPort( savedPort ) ;
  3980.  
  3981.     return theError ;
  3982. }
  3983.  
  3984.  
  3985.     
  3986. WindowPtr ViewerWindow_Open( FSSpec *theFSSpec )
  3987. {
  3988.     OSErr                theError ;
  3989.     short                theRef ;
  3990.     WindowPtr            theWindow ;
  3991.     TQ3ViewerObject        theViewer ;
  3992.     DocumentHdl    theDocumentHdl ;
  3993.  
  3994.     /* open the file  */
  3995.     theError = FSpOpenDF( theFSSpec, fsRdPerm, &theRef ) ;
  3996.     
  3997.     if( theError == noErr )
  3998.     {                    
  3999.         theWindow = DoCreateNewViewerWindow( theFSSpec->name) ;
  4000.         
  4001.         if( theWindow != NULL )
  4002.         {
  4003.             
  4004.             theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4005.             if(theDocumentHdl != NULL 
  4006.                 && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  4007.             {
  4008.                 /* get the viewer object from the document */
  4009.                 ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  4010.                 if( theViewerHdl != NULL )
  4011.                 {
  4012.                     HLock((Handle)theViewerHdl) ;
  4013.                     if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4014.                     {
  4015.                         (**theViewerHdl).fFSSpec = *theFSSpec ;
  4016.                         theError = Q3ViewerUseFile( theViewer, theRef );
  4017.                         if( theError == noErr )
  4018.                             theError = FSClose ( theRef ) ;
  4019.                     }
  4020.                     HUnlock((Handle)theViewerHdl) ;
  4021.                 }
  4022.             }
  4023.         }
  4024.     }
  4025.     return theWindow ;
  4026. }    
  4027.         
  4028. /*------------------------------------------------------------ */
  4029.  
  4030. /*
  4031.  * handles the close menu item in the file menu
  4032.  * close the window after disposing of the associated
  4033.  * data structures (viewer, etc).
  4034.  */
  4035.  
  4036.  
  4037. OSErr ViewerWindow_Close( WindowPtr theWindow )
  4038. {
  4039.  
  4040.     OSErr                theError = paramErr ;
  4041.  
  4042.  
  4043.     TQ3ViewerObject        theViewer ;
  4044.  
  4045.     DocumentHdl    theDocumentHdl ;
  4046.  
  4047.  
  4048.     /* this option can't be selected unless there is a frontwindow  */
  4049.     /* the option is dimmed in adjustmenus if there is no window  */
  4050.     if( theWindow != NULL )        /* sanity check  */
  4051.     {
  4052.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4053.         if(theDocumentHdl != NULL 
  4054.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic) 
  4055.         {
  4056.             /* get the viewer object from the document */
  4057.             ViewerDataHdl        theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate) ;
  4058.  
  4059.             /* dispose of the print record for the document */
  4060.             THPrint    thePrintRec = (**theDocumentHdl).fPrintRec ;
  4061.             if( thePrintRec != NULL )
  4062.                 DisposeHandle((Handle)thePrintRec ) ;
  4063.  
  4064.             if( theViewerHdl != NULL )
  4065.             {
  4066.                 HLock((Handle)theViewerHdl) ;
  4067.                 if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4068.                 {
  4069.                     theError = Q3ViewerDispose( theViewer ) ;
  4070.                     if( theError == noErr )
  4071.                         DisposeWindow( theWindow ) ;
  4072.                 }
  4073.                 HUnlock((Handle)theViewerHdl) ;
  4074.             }
  4075.         }
  4076.     }
  4077.     return theError ;
  4078.             
  4079. }
  4080. /*------------------------------------------------------------ */
  4081.  
  4082. /*
  4083.  * handle event for a viewer window
  4084.  */
  4085.  
  4086.  
  4087. Boolean    ViewerWindow_HandleEvent( WindowPtr theWindow, const EventRecord *theEventRecord)
  4088. {
  4089.  
  4090.     GrafPtr                savedPort ;
  4091.     short               thePart;
  4092.     Rect                screenRect;
  4093.     Rect                growRect ;
  4094.     Point                aPoint = {100, 100};
  4095.     GrafPtr                oldPort ;
  4096.     Boolean                eventWasHandled ;
  4097.     unsigned long        width ;
  4098.     unsigned long        height ;
  4099.     long                newSize ;
  4100.     OSErr                theErr ;
  4101.     Point                mouseLoc ;
  4102.     TQ3Boolean             handledEvent = kQ3False ;
  4103.     TQ3ViewerObject        theViewer = NULL ;
  4104.     DocumentHdl            theDocumentHdl ;
  4105.     ViewerDataHdl        theViewerHdl ;
  4106.       
  4107.       /* 
  4108.        * check to see if the event is a viewer event, also since
  4109.        * the update event processing needs to be done between begin update
  4110.        * and end update, don't handle updates here for viewer objects
  4111.        */
  4112.       if( theWindow != NULL && theEventRecord->what != updateEvt)
  4113.       {        
  4114.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4115.         if(theDocumentHdl != NULL) 
  4116.         {
  4117.             if((**theDocumentHdl).fDocumentMagic == kViewerMagic 
  4118.                 && ((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate))) != NULL
  4119.                 && (theViewer = (**theViewerHdl).fViewer) != NULL ) 
  4120.             {
  4121.                  /*
  4122.                    * There is a bug in versions 1.0.4 and earlier of the Viewer,
  4123.                    * so the port has to be set and restored.
  4124.                    */
  4125.                    
  4126.                 GetPort( &oldPort ) ;
  4127.                 SetPort((GrafPtr)theWindow ) ;
  4128.  
  4129.                 eventWasHandled = Q3ViewerEvent( theViewer, (EventRecord *)theEventRecord );
  4130.                 DoDrawGrowIcon(theWindow) ;
  4131.                 GetMouse( &mouseLoc ) ;
  4132.                 Q3ViewerAdjustCursor( theViewer,  &mouseLoc );
  4133.                 
  4134.                 /* restore the port */
  4135.                 SetPort( oldPort ) ;
  4136.                 
  4137.                 /* 
  4138.                  * if the window is not the frontmost 
  4139.                  * window, give the eventhandler 
  4140.                  * a chance to process the event.
  4141.                  */
  4142.                 if(theWindow != FrontWindow())
  4143.                     eventWasHandled = false ;
  4144.                     
  4145.             }
  4146.         }
  4147.         
  4148.     }
  4149.     else
  4150.     {
  4151.         eventWasHandled = false ;
  4152.     }
  4153.     return eventWasHandled ;
  4154. }
  4155.  
  4156.  
  4157. /*------------------------------------------------------------ */
  4158.  
  4159. /*
  4160.  * handle update for a viewer window
  4161.  */
  4162.  
  4163. void    ViewerWindow_Update(WindowPtr  theWindow)
  4164. {
  4165.     GrafPtr                oldPort ;
  4166.     DocumentHdl            theDocumentHdl ;
  4167.     ViewerDataHdl        theViewerHdl ;
  4168.     TQ3ViewerObject        theViewer ;
  4169.     OSErr                theErr ;
  4170.     
  4171.     GetPort( &oldPort ) ;    
  4172.     SetPort( theWindow );
  4173.     BeginUpdate( theWindow );
  4174.     {
  4175.         theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4176.         if(theDocumentHdl != NULL
  4177.             && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4178.             && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4179.         {
  4180.             if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4181.             {
  4182.                 theErr = Q3ViewerDraw( theViewer );
  4183.                 DoDrawGrowIcon(theWindow) ;
  4184.             }
  4185.         }
  4186.     }
  4187.     EndUpdate( theWindow );
  4188.     SetPort( oldPort ) ;
  4189. }
  4190.  
  4191. /*------------------------------------------------------------ */
  4192.  
  4193. /*
  4194.  * make sure that menus are enabled and disabled in an
  4195.  * appropriate manner for the case where the front window 
  4196.  * is a viewer window.
  4197.  */
  4198.  
  4199. void ViewerWindow_AdjustMenus( WindowPtr  theWindow )
  4200. {
  4201.         
  4202.     MenuHandle            theMenu ;
  4203.     DocumentHdl            theDocumentHdl ;
  4204.     ViewerDataHdl        theViewerHdl ;
  4205.     TQ3ViewerObject        theViewer ;
  4206.     TQ3ViewObject         myView ;
  4207.     TQ3Status            myStatus ;
  4208.     TQ3RendererObject    myRenderer ;
  4209.     TQ3ObjectType        theRendererType ;
  4210.     long                tmpLong, theScrapOffset ;
  4211.     unsigned long        theViewerFlags;
  4212.     unsigned long        theViewerState ;
  4213.     
  4214.     char                itemString[255] ;
  4215.     unsigned long        itemStringLength ;
  4216.  
  4217.     /*
  4218.      * get the reference to our viewer document data structure
  4219.      * from the long reference constant for the window.  Cast
  4220.      * it to the appropriate type.  If we can't get it (i.e. it's
  4221.      * null we want to bail
  4222.      */
  4223.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4224.     if(theDocumentHdl == NULL) 
  4225.         return ;
  4226.         
  4227.     /* get the reference to the viewer object from our data structure  */    
  4228.     if((theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) == NULL)
  4229.         return ;
  4230.     
  4231.     /* get the reference to the viewer object from our data structure  */    
  4232.     theViewer = (**theViewerHdl).fViewer ;
  4233.     if(theViewer == NULL) 
  4234.         return ;
  4235.         
  4236.     /* get the viewer state, we need to know if it is empty  */    
  4237.     theViewerState = Q3ViewerGetState( theViewer ) ;
  4238.     
  4239.     /* adjust the file menu  */
  4240.     theMenu = GetMenuHandle ( mFileMenu ) ;
  4241.     
  4242.     EnableItem ( theMenu, iFileNewItem );        /* always enabled  */
  4243.     EnableItem ( theMenu, iFileOpenItem );        /* always enabled  */
  4244.     EnableItem ( theMenu, iFileQuitItem );        /* always enabled  */
  4245.  
  4246.     EnableItem ( theMenu, iFileCloseItem );
  4247.     
  4248.     if( ((theViewerState & kQ3ViewerHasModel) ? true : false ) ) 
  4249.     {
  4250.         EnableItem ( theMenu, iFileSaveItem );
  4251.         EnableItem ( theMenu, iFileSaveAsItem );
  4252.         EnableItem ( theMenu, iFileRevertItem );
  4253.         EnableItem ( theMenu, iFilePageSetupItem );
  4254.         EnableItem ( theMenu, iFilePrintItem );
  4255.     }
  4256.     else
  4257.     {
  4258.         DisableItem ( theMenu, iFileSaveItem );
  4259.         DisableItem ( theMenu, iFileSaveAsItem );
  4260.         DisableItem ( theMenu, iFileRevertItem );
  4261.         DisableItem ( theMenu, iFilePageSetupItem );
  4262.         DisableItem ( theMenu, iFilePrintItem );
  4263.     }
  4264.     
  4265.     
  4266.     /* adjust the edit menu  */
  4267.     theMenu = GetMenuHandle ( mEditMenu ) ;
  4268.     EnableItem ( theMenu, 0L );
  4269.     
  4270.     if( ((theViewerState & kQ3ViewerHasUndo) ? true : false ) ) 
  4271.     {
  4272.         /* undo is possible, get the string for this item and enable it */
  4273.         Boolean        canUndo ;
  4274.         
  4275.         /*
  4276.          * Hokeyness alert.  We pass in the address of the second element of 
  4277.          * the itemString array, allowing us to set the length later in the
  4278.          * first element of the array, saving us the need to to an inplace
  4279.          * C to P string conversion (the Mac toolbox routines require a 
  4280.          * pascal format string that has the length as the first byte.
  4281.          */
  4282.         canUndo = Q3ViewerGetUndoString( theViewer, &itemString[1], &itemStringLength );
  4283.         itemString[0] = (char)itemStringLength ;
  4284.                         
  4285.         /* if we can undo then enable the new string, else use the default cant undo string */
  4286.         if( canUndo == true && itemStringLength > 0 )
  4287.         {    
  4288.             SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4289.             EnableItem ( theMenu, iEditUndoItem );
  4290.         }    
  4291.         else 
  4292.         {
  4293.             GetIndString ( (unsigned char *)itemString, 2223, 1 ) ;
  4294.             SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4295.             DisableItem ( theMenu, iEditUndoItem );    
  4296.         }
  4297.     }
  4298.     else
  4299.     {
  4300.         GetIndString ( (unsigned char *)itemString, 2223, 1 ) ;
  4301.         SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4302.         DisableItem ( theMenu, iEditUndoItem );    
  4303.     }
  4304.  
  4305.     if( ((theViewerState & kQ3ViewerHasModel) ? true : false ) ) 
  4306.     {
  4307.         EnableItem ( theMenu, iEditCutItem );
  4308.         EnableItem ( theMenu, iEditCopyItem );
  4309.         EnableItem ( theMenu, iEditClearItem );
  4310.     }
  4311.     else
  4312.     {
  4313.         DisableItem ( theMenu, iEditCutItem );
  4314.         DisableItem ( theMenu, iEditCopyItem );
  4315.         DisableItem ( theMenu, iEditClearItem );
  4316.     }
  4317.     
  4318.     
  4319.     /*
  4320.      * check that there is some data that we can paste.  GetScrap returns
  4321.      * a long that gives either the length of the requested type, or a
  4322.      * negative error code that is used to indicate that no such type exists
  4323.      */
  4324.     
  4325.     tmpLong = GetScrap( nil, '3DMF', &theScrapOffset ) ;
  4326.     if( tmpLong < 0 )
  4327.         DisableItem ( theMenu, iEditPasteItem );
  4328.     else
  4329.         EnableItem ( theMenu, iEditPasteItem );
  4330.         
  4331.  
  4332.     
  4333.     /* adjust the view menu  */
  4334.     theMenu = GetMenuHandle ( mViewMenu ) ;
  4335.     EnableItem ( theMenu, 0L );
  4336.     
  4337.     /*
  4338.      * since most of the items in this menu rely on adjusting
  4339.      * the viewer flags, we'll get the flags here so we can
  4340.      * bitwise manipulate them in the switch below
  4341.      */ 
  4342.     theViewerFlags = Q3ViewerGetFlags( theViewer ) ;
  4343.     
  4344.     /*
  4345.      * check each of the items that have their flag
  4346.      * bits set to true in the viewer flags.
  4347.      *
  4348.      * Note that the Boolean flag for CheckItem is defined
  4349.      * (( theViewerFlags & kQ3ViewerShowBadge ) ? true : false)
  4350.      * and so on.  The reson for this is that simply adding
  4351.      * ( theViewerFlags & kQ3ViewerShowBadge ) won't be sufficient
  4352.      * if the flag is the 8th bit or more of the unsigned long 
  4353.      * defined to hold the flages, since the param passed will 
  4354.      * only be the first 8 bits (of couse this is dependent on
  4355.      * the develolment system size for Boolean, but this is true
  4356.      * for CodeWarrior.
  4357.      */
  4358.     
  4359.     CheckItem( theMenu, iViewBadgeItem, (( theViewerFlags & kQ3ViewerShowBadge ) ? true : false)) ;
  4360.     CheckItem( theMenu, iViewCameraButtonItem, (( theViewerFlags & kQ3ViewerButtonCamera ) ? true : false)) ;
  4361.     CheckItem( theMenu, iViewTruckButtonItem, (( theViewerFlags & kQ3ViewerButtonTruck ) ? true : false)) ;
  4362.     CheckItem( theMenu, iViewOrbitButtonItem, (( theViewerFlags & kQ3ViewerButtonOrbit ) ? true : false)) ;
  4363.     CheckItem( theMenu, iViewZoomButtonItem, (( theViewerFlags & kQ3ViewerButtonZoom ) ? true : false)) ;
  4364.     CheckItem( theMenu, iViewDollyButtonItem, (( theViewerFlags & kQ3ViewerButtonDolly ) ? true : false)) ;
  4365.     CheckItem( theMenu, iViewInsetNFrameItem, (( theViewerFlags & kQ3ViewerDrawFrame ) ? true : false)) ;
  4366.     
  4367.     /* adjust the renderer menu  */
  4368.     theMenu = GetMenuHandle ( mInteractiveRendererMenu ) ;
  4369.     
  4370.     /*
  4371.      * get the renderer for the view
  4372.      */
  4373.     myView = Q3ViewerGetView( theViewer );
  4374.     if( myView != NULL )
  4375.     {
  4376.         long                    rendererIndex = 0 ;
  4377.         MenuHandle                tempMenu ;
  4378.         
  4379.         /* set the renderer to the one created in the switch statement above */
  4380.         myStatus = Q3View_GetRenderer(myView, &myRenderer) ;
  4381.         theRendererType = Q3Renderer_GetType( myRenderer ) ;
  4382.         
  4383.         for( rendererIndex = 0; pInteractiveTypes[ rendererIndex ] ; rendererIndex++ ) 
  4384.         {
  4385.             CheckItem( theMenu, rendererIndex+1,  (theRendererType == pInteractiveTypes[rendererIndex])) ;
  4386.         }
  4387.         
  4388.         /*
  4389.          * Update the edit renderer prefs "edit menu" item.  Should probably be done with 
  4390.          * the edit menu stuff, I put this here because we have a reference
  4391.          * to the renderer here
  4392.          */
  4393.                 
  4394.         /* enable the menu item appropriately */
  4395.         tempMenu = GetMenuHandle ( mEditMenu ) ;
  4396.         if( Q3Renderer_HasModalConfigure(myRenderer) )
  4397.             EnableItem ( tempMenu, iEditRendererPrefsItem );
  4398.         else
  4399.             DisableItem ( tempMenu, iEditRendererPrefsItem );
  4400.  
  4401.         /* 
  4402.          * getting the renderer incremented the ref count for it,
  4403.          * we can dispose of the reference to it 
  4404.          */
  4405.         myStatus = Q3Object_Dispose( myRenderer ) ;            
  4406.     }
  4407. }
  4408.  
  4409. /*------------------------------------------------------------ */
  4410.  
  4411. /*
  4412.  * ViewerWindow_CountPages - calculate the number of pages needed to
  4413.  * image the document associated with the viewer window.  For now we
  4414.  * assume 1.
  4415.  */
  4416.  
  4417.  
  4418. short    ViewerWindow_CountPages( 
  4419.     WindowPtr    theWindow, 
  4420.     Rect         *pageRect ) 
  4421. {
  4422.     Rect            pictRect ;
  4423.     short            horizOffset, 
  4424.                     vertOffset,
  4425.                     pagesWide = 0,     /*  the number of pages wide the image is */
  4426.                     pagesHigh = 0,     /*  the number pages high for this image */
  4427.                     pageWidth,         /*  the width of one page */
  4428.                     pageHeight ;    /*  the height of one page */
  4429.  
  4430.     DocumentHdl        theDocumentHdl ;
  4431.     ViewerDataHdl    theViewerHdl ;
  4432.     GWorldPtr        theGWorld ;
  4433.     OSErr            theErr ;
  4434.     
  4435.     short            retVal = 0 ;
  4436.     
  4437.     PicHandle        thePicture ;
  4438.     
  4439.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4440.     if(theDocumentHdl != NULL
  4441.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4442.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4443.     {
  4444.         if((theGWorld = (**theViewerHdl).fGWorld) != NULL) 
  4445.         {
  4446.             retVal = GeneralCountPages( theGWorld, pageRect ) ;
  4447.         }
  4448.     }
  4449.     
  4450.     return retVal ;
  4451. }
  4452.  
  4453. /*------------------------------------------------------------ */
  4454.  
  4455. /*
  4456.  * ViewerWindow_PrintPage - image the requested page in the 
  4457.  * printer port
  4458.  */
  4459.  
  4460. void    ViewerWindow_PrintPage( 
  4461.     WindowPtr         theWindow, 
  4462.     Rect             *pageRect, 
  4463.     GrafPtr         imagingPort, 
  4464.     short             pageNum ) 
  4465. {
  4466.     GWorldPtr        theGWorld;
  4467.     Rect            pictRect, rectToPrint,srcRect,dstRect;
  4468.     short            pagesWide,         /*  the number of pages wide the image is */
  4469.                     pagesHigh,         /*  the number pages high for this image */
  4470.                     horozTile,         /*  used in the loop to denote the H tile to print from the image */
  4471.                     vertTile ;         /*  used in the loop to denote the V tile to print from the image */
  4472.     short            thisPage = 1;    /*  used to find the page they want us to print */
  4473.     short            pictHOff,
  4474.                     pictVOff,
  4475.                     pictWidth,         /*  the width of the doc's GWorld */
  4476.                     pictHeight ;    /*  the height of the doc's GWorld */
  4477.     short            pageWidth,         /*  the width of one page */
  4478.                     pageHeight ;    /*  the height of one page */
  4479.     OSErr            theErr ;
  4480.     PixMapHandle    offPixMap ;
  4481.     DocumentHdl        theDocumentHdl ;
  4482.     ViewerDataHdl    theViewerHdl ;
  4483.     TQ3ViewerObject    theViewer ;
  4484.  
  4485.  
  4486.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4487.     if(theDocumentHdl != NULL
  4488.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4489.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4490.     {
  4491.         if((theGWorld = (**theViewerHdl).fGWorld) != NULL) 
  4492.         {
  4493.             GeneralPrintPage( theGWorld, pageRect, imagingPort, pageNum ) ;
  4494.         }
  4495.     }
  4496. }
  4497.  
  4498.  
  4499. /*------------------------------------------------------------ */
  4500.  
  4501. /*
  4502.  * ViewerWindow_PrePrint - this gets called before we print, so any
  4503.  * setup for printing can be done here.
  4504.  */
  4505. void ViewerWindow_PrePrint( WindowPtr theWindow )
  4506. {
  4507.     /*
  4508.      * before we print we want to get a pixmap that represents the 
  4509.      * current document being imaged.  We use Q3ViewerGetPict to 
  4510.      * do this and use the fGWorld field of the viewer's data
  4511.      * to store this until it's been imaged.  Not efficient, but
  4512.      * that's the price of using the viewer.
  4513.      */
  4514.     DocumentHdl            theDocumentHdl ;
  4515.     ViewerDataHdl        theViewerHdl ;
  4516.     TQ3ViewerObject        theViewer ;
  4517.  
  4518.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4519.     if(theDocumentHdl != NULL
  4520.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4521.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4522.     {
  4523.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4524.         {
  4525.             PicHandle        thePicture ;
  4526.                         GWorldPtr        theGWorld ;
  4527.             Rect            pictRect ;
  4528.             OSErr            theErr ;
  4529.             GrafPtr            savedPort ;
  4530.  
  4531.             GetPort( &savedPort ) ;
  4532.             SetPort( (GrafPtr) theWindow ) ;
  4533.             
  4534.             thePicture = Q3ViewerGetPict( theViewer ) ;
  4535.             
  4536.             SetPort( savedPort ) ;
  4537.             
  4538.             if( thePicture != NULL )
  4539.             {
  4540.                 pictRect.top    = (**thePicture).picFrame.top ;
  4541.                 pictRect.left    = (**thePicture).picFrame.left ;
  4542.                 pictRect.bottom    = (**thePicture).picFrame.bottom ;
  4543.                 pictRect.right    = (**thePicture).picFrame.right ;
  4544.                 
  4545.                 /* make sure the GWorld's origin is (0,0) */
  4546.                 OffsetRect( &pictRect, -pictRect.left, -pictRect.top ) ;
  4547.                 
  4548.                 /* make a new offscreen world */
  4549.                 theErr =  NewGWorld( &theGWorld, 32, &pictRect, NULL, NULL, 0L );
  4550.                 if( theErr == noErr && theGWorld != NULL )
  4551.                 {
  4552.                     PixMapHandle            offPixMap ;
  4553.                     CGrafPtr                savedPort ;
  4554.                     GDHandle                gdh ;
  4555.                     
  4556.                     /* image the picture into the offscreen */
  4557.                     GetGWorld( &savedPort, &gdh ) ;
  4558.                     SetGWorld( theGWorld, NULL ) ;
  4559.                     
  4560.                     /* get the gworld pixmap and lock it down */
  4561.                     offPixMap = GetGWorldPixMap( theGWorld ) ;
  4562.                     (void) LockPixels( offPixMap ) ;
  4563.                 
  4564.                     /* draw the Picture in the port */
  4565.                     DrawPicture( thePicture, &theGWorld->portRect ) ;
  4566.                     
  4567.                     /* unlock the pixmap */
  4568.                     (void) UnlockPixels( offPixMap ) ;
  4569.                         
  4570.                     SetGWorld( savedPort, gdh ) ;
  4571.                     (**theViewerHdl).fGWorld = theGWorld;
  4572.                 
  4573.                 }
  4574.                 else
  4575.                 {
  4576.                     (**theViewerHdl).fGWorld = NULL;
  4577.                 }
  4578.                 
  4579.                 /* ditch the pict */
  4580.                 KillPicture( thePicture ) ;
  4581.  
  4582.             }
  4583.             else
  4584.             {
  4585.                 (**theViewerHdl).fGWorld = NULL ;
  4586.             }
  4587.         }
  4588.     }
  4589.      
  4590.     return ; 
  4591. }
  4592.  
  4593.  
  4594. /*------------------------------------------------------------ */
  4595.  
  4596. /*
  4597.  * ViewerWindow_PostPrint - this gets called before we print, so any
  4598.  * setup for printing can be done here.
  4599.  */
  4600. void ViewerWindow_PostPrint( WindowPtr theWindow )
  4601. {
  4602.     /* delete the cached pict */
  4603.     DocumentHdl            theDocumentHdl ;
  4604.     ViewerDataHdl        theViewerHdl ;
  4605.     TQ3ViewerObject        theViewer ;
  4606.  
  4607.  
  4608.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4609.     if(theDocumentHdl != NULL
  4610.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4611.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4612.     {
  4613.         GWorldPtr        theGWorld = (**theViewerHdl).fGWorld ;
  4614.         
  4615.         /* get rid of the gworld */
  4616.         DisposeGWorld(theGWorld);
  4617.         (**theViewerHdl).fGWorld = NULL ;
  4618.     }
  4619.      
  4620.     return ; 
  4621. }
  4622.  
  4623. /*------------------------------------------------------------ */
  4624.  
  4625. /*
  4626.  * Handle the edit menu cut command for this window type
  4627.  */
  4628. OSErr        ViewerWindow_Cut( WindowPtr    theWindow ) 
  4629. {
  4630.     DocumentHdl            theDocumentHdl ;
  4631.     ViewerDataHdl        theViewerHdl ;
  4632.     TQ3ViewerObject        theViewer ;
  4633.     OSErr                theError = paramErr ;
  4634.  
  4635.  
  4636.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4637.     if(theDocumentHdl != NULL
  4638.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4639.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4640.     {
  4641.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4642.         {
  4643.             theError = Q3ViewerCut ( theViewer ) ;
  4644.         }
  4645.     }
  4646.      
  4647.     return theError ; 
  4648.  
  4649. }
  4650.  
  4651. /*------------------------------------------------------------ */
  4652.  
  4653. /*
  4654.  * Handle the edit menu copy command for this window type
  4655.  */
  4656. OSErr        ViewerWindow_Copy( WindowPtr    theWindow ) 
  4657. {
  4658.  
  4659.     DocumentHdl            theDocumentHdl ;
  4660.     ViewerDataHdl        theViewerHdl ;
  4661.     TQ3ViewerObject        theViewer ;
  4662.     OSErr                theError = paramErr ;
  4663.  
  4664.  
  4665.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4666.     if(theDocumentHdl != NULL
  4667.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4668.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4669.     {
  4670.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4671.         {
  4672.             theError = Q3ViewerCopy ( theViewer ) ;
  4673.         }
  4674.     }
  4675.      
  4676.     return theError ; 
  4677.  
  4678. }
  4679.  
  4680. /*------------------------------------------------------------ */
  4681.  
  4682. /*
  4683.  * Handle the edit menu paste command for this window type
  4684.  */
  4685. OSErr        ViewerWindow_Paste( WindowPtr    theWindow ) 
  4686. {
  4687.  
  4688.     DocumentHdl            theDocumentHdl ;
  4689.     ViewerDataHdl        theViewerHdl ;
  4690.     TQ3ViewerObject        theViewer ;
  4691.     OSErr                theError = paramErr ;
  4692.  
  4693.  
  4694.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4695.     if(theDocumentHdl != NULL
  4696.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4697.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4698.     {
  4699.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4700.         {
  4701.             theError = Q3ViewerPaste ( theViewer ) ;
  4702.         }
  4703.     }
  4704.      
  4705.     return theError ; 
  4706.  
  4707. }
  4708.  
  4709. /*------------------------------------------------------------ */
  4710.  
  4711. /*
  4712.  * Handle the edit menu clear command for this window type
  4713.  */
  4714. OSErr        ViewerWindow_Clear( WindowPtr    theWindow )
  4715. {
  4716.  
  4717.     DocumentHdl            theDocumentHdl ;
  4718.     ViewerDataHdl        theViewerHdl ;
  4719.     TQ3ViewerObject        theViewer ;
  4720.     OSErr                theError = paramErr ;
  4721.  
  4722.  
  4723.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4724.     if(theDocumentHdl != NULL
  4725.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4726.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4727.     {
  4728.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4729.         {
  4730.             theError = Q3ViewerClear ( theViewer ) ;
  4731.         }
  4732.     }
  4733.      
  4734.     return theError ; 
  4735.  
  4736. }
  4737.  
  4738. /*------------------------------------------------------------ */
  4739.  
  4740. /*
  4741.  * Handle the edit menu undo command for this window type
  4742.  */
  4743. OSErr        ViewerWindow_Undo( WindowPtr    theWindow )
  4744. {
  4745.  
  4746.     DocumentHdl            theDocumentHdl ;
  4747.     ViewerDataHdl        theViewerHdl ;
  4748.     TQ3ViewerObject        theViewer ;
  4749.     OSErr                theError = paramErr ;
  4750.  
  4751.  
  4752.  
  4753.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4754.     if(theDocumentHdl != NULL
  4755.         && (**theDocumentHdl).fDocumentMagic == kViewerMagic
  4756.         && (theViewerHdl = (ViewerDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4757.     {
  4758.         if((theViewer = (**theViewerHdl).fViewer) != NULL) 
  4759.         {
  4760.             theError = Q3ViewerUndo ( theViewer ) ;
  4761.         }
  4762.     }
  4763.      
  4764.     return theError ; 
  4765.  
  4766. }
  4767.  
  4768. /*------------------------------------------------------------ */
  4769.  
  4770. /*
  4771.  * Get an output reference for a PICT file
  4772.  */
  4773. OSErr GetOutputPictFileRef(short    *dstPictFRef ) 
  4774. {
  4775.     StandardFileReply    aPictSFR;    /* new style Standard file record */
  4776.     OSErr                result ;
  4777.     SFTypeList     types = { 'PICT',0 };    /* we are only interested in PICT files */
  4778.         
  4779.     StandardPutFile( "\pSave PICT as:", "\pNew PICT", &aPictSFR ) ;
  4780.     if ( aPictSFR.sfGood  ) {
  4781.         
  4782.         /* 
  4783.          * Delete the file of the same name, if one exits, 
  4784.          * and create a new PICT file.
  4785.          */
  4786.         
  4787.         FSpDelete(&aPictSFR.sfFile);
  4788.         
  4789.         result = FSpCreate( &aPictSFR.sfFile,'????','PICT', aPictSFR.sfScript);
  4790.         if (result != noErr) {
  4791.             return result;
  4792.         }
  4793.         
  4794.         /* open the data fork for writing */
  4795.         
  4796.         result = FSpOpenDF( &aPictSFR.sfFile, fsCurPerm, dstPictFRef);
  4797.         if (result != noErr) {
  4798.             return result;
  4799.         }
  4800.     }
  4801.     else 
  4802.         return userCanceledErr ;
  4803.         
  4804.     return noErr ;
  4805. }
  4806.  
  4807. /*------------------------------------------------------------ */
  4808.  
  4809. /*
  4810.  * create a new viewer document window, this includes creating a
  4811.  * document record, a window and an associated viewer object.  the
  4812.  * document record is stored in the window's refcon field, so it
  4813.  * can be accessed as required via the window record.
  4814.  */
  4815.  
  4816. WindowPtr DoCreateNewPictWindow( unsigned char *windowName, long windWidth, long windHeight )
  4817. {
  4818.     WindowPtr            theWindow ;
  4819.     Rect                myRect ;
  4820.     TQ3ViewerObject        myViewer ;
  4821.     DocumentHdl            myPictDocument = NULL ;
  4822.     GWorldPtr            myGWorld ;
  4823.     PictDataHdl        myViewerPict ;
  4824.     
  4825.     myRect.top = 0 ;
  4826.     myRect.left = 0 ;
  4827.     myRect.bottom = windHeight ;
  4828.     myRect.right = windWidth ;
  4829.  
  4830.     /* create a document record to hold the  */
  4831.     /* data for this instance  */
  4832.     if((myPictDocument = (DocumentHdl)NewHandleClear(sizeof(Document))) == NULL)
  4833.         return NULL ;
  4834.     
  4835.     /* make a GWorld the size requested */
  4836.     if(NewGWorld ( &myGWorld, 32, &myRect, NULL, NULL, 0L ) != noErr)
  4837.         return NULL ;
  4838.         
  4839.     
  4840.     /* ideally we should stagger the window rect  */
  4841.     
  4842.     OffsetRect( &myRect, 50, 50 ) ; 
  4843.                       
  4844.     theWindow = NewCWindow( NULL, 
  4845.                          &myRect, 
  4846.                          windowName, 
  4847.                          true, 
  4848.                          documentProc, 
  4849.                          (WindowPtr)-1, 
  4850.                          true, 
  4851.                          0L ) ;
  4852.                          
  4853.     myViewerPict = (PictDataHdl)NewHandleClear(sizeof(PictData)) ;
  4854.     if(myViewerPict == NULL)
  4855.     {
  4856.         DisposeHandle( (Handle)myPictDocument ) ;
  4857.         return NULL ;
  4858.     }
  4859.         
  4860.     /* put the magic cookie in the first field so we can identify this as a valid pict */
  4861.     (**myPictDocument).fDocumentMagic = kPICTMagic ;
  4862.     
  4863.     /* set up the procs field */
  4864.     (**myPictDocument).procs = &pictProcs ;
  4865.     
  4866.     /* set up the private data part of the document structure */
  4867.     (**myViewerPict).fGWorld = myGWorld ;
  4868.     
  4869.     (**myPictDocument).fPrivate = (void *)myViewerPict ;
  4870.     
  4871.     /* finally create a new print record */
  4872.     DoCreatePrintRecord( myPictDocument ) ;
  4873.  
  4874.     /* store a reference to the document structure in the refcon
  4875.      * field of the window  
  4876.      */
  4877.     SetWRefCon( theWindow, (long)myPictDocument ) ;
  4878.     
  4879.     return theWindow ;
  4880. }
  4881.  
  4882.  
  4883. /*------------------------------------------------------------ */
  4884.  
  4885. /*
  4886.  * PictWindow_Update
  4887.  */
  4888. void            PictWindow_Update( WindowPtr  theWindow ) 
  4889. {
  4890.     GrafPtr                oldPort ;
  4891.     DocumentHdl            theDocumentHdl ;
  4892.     PictDataHdl            thePictDataHdl ;
  4893.     GWorldPtr            theGWorld ;
  4894.     OSErr                theErr ;
  4895.     
  4896.     GetPort( &oldPort ) ;    
  4897.     SetPort( theWindow );
  4898.     BeginUpdate( theWindow );
  4899.  
  4900.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4901.     if(theDocumentHdl != NULL
  4902.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  4903.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  4904.     {
  4905.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  4906.         {
  4907.             /* copybits from the GWorld here */
  4908.             
  4909.             CopyBits ((BitMapPtr) &theGWorld->portPixMap,
  4910.                       &theWindow->portBits,
  4911.                       &theGWorld->portRect, 
  4912.                       &theWindow->portRect,
  4913.                       srcCopy, 
  4914.                       0L);
  4915.             DoDrawGrowIcon(theWindow) ;
  4916.         }
  4917.     }
  4918.     
  4919.     EndUpdate( theWindow );
  4920.     SetPort( oldPort ) ;
  4921. }
  4922.  
  4923.  
  4924. /*------------------------------------------------------------ */
  4925.  
  4926. /*
  4927.  * PictWindow_AdjustMenus
  4928.  */
  4929. void             PictWindow_AdjustMenus( WindowPtr  theWindow ) 
  4930. {
  4931.         
  4932.     MenuHandle            theMenu ;
  4933.     DocumentHdl            theDocumentHdl ;
  4934.     ViewerDataHdl        theViewerHdl ;
  4935.     TQ3ViewerObject        theViewer ;
  4936.     TQ3ViewObject         myView ;
  4937.     TQ3Status            myStatus ;
  4938.     TQ3RendererObject    myRenderer ;
  4939.     TQ3ObjectType        theRendererType ;
  4940.     long                tmpLong, theScrapOffset ;
  4941.     unsigned long        theViewerFlags;
  4942.     unsigned long        theViewerState ;
  4943.     
  4944.     char                itemString[255] ;
  4945.     unsigned long        itemStringLength ;
  4946.  
  4947.     /*
  4948.      * get the reference to our Pict document data structure
  4949.      * from the long reference constant for the window.  Cast
  4950.      * it to the appropriate type.  If we can't get it (i.e. it's
  4951.      * null we want to bail
  4952.      */
  4953.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  4954.     if(theDocumentHdl == NULL) 
  4955.         return ;
  4956.         
  4957.     /* adjust the file menu  */
  4958.     theMenu = GetMenuHandle ( mFileMenu ) ;
  4959.     
  4960.     EnableItem ( theMenu, iFileNewItem );        /* always enabled  */
  4961.     EnableItem ( theMenu, iFileOpenItem );        /* always enabled  */
  4962.     EnableItem ( theMenu, iFileQuitItem );        /* always enabled  */
  4963.  
  4964.     EnableItem ( theMenu, iFileCloseItem );
  4965.     
  4966.     /* 
  4967.      * this only gets called if we have a pict window in the first 
  4968.      * place so enable saving and printing...
  4969.      */
  4970.     EnableItem ( theMenu, iFileSaveItem );
  4971.     EnableItem ( theMenu, iFileSaveAsItem );
  4972.     EnableItem ( theMenu, iFileRevertItem );
  4973.     EnableItem ( theMenu, iFilePageSetupItem );
  4974.     EnableItem ( theMenu, iFilePrintItem );
  4975.  
  4976.     /* adjust the edit menu  */
  4977.     theMenu = GetMenuHandle ( mEditMenu ) ;
  4978.     EnableItem ( theMenu, 0L );
  4979.     
  4980.     /* 
  4981.      * there's not really anything to undo with this window type so set 
  4982.      * the undo string to "Can't Undo"
  4983.      */
  4984.     GetIndString ( (unsigned char *)itemString, 2223, 1 ) ;
  4985.     SetMenuItemText ( theMenu, iEditUndoItem, (unsigned char *)itemString ) ;
  4986.     
  4987.     
  4988.     DisableItem ( theMenu, iEditUndoItem );    
  4989.  
  4990.     /* enable copy */
  4991.     EnableItem ( theMenu, iEditCopyItem );
  4992.     
  4993.     /* disable cut, paste and clear */
  4994.     DisableItem ( theMenu, iEditClearItem );
  4995.     DisableItem ( theMenu, iEditPasteItem );
  4996.     DisableItem ( theMenu, iEditCutItem );
  4997.     
  4998.     /* disable the renderer prefs */
  4999.     DisableItem ( theMenu, iEditRendererPrefsItem );
  5000.                 
  5001.     /* adjust the view menu  */
  5002.     theMenu = GetMenuHandle ( mViewMenu ) ;
  5003.     DisableItem ( theMenu, 0L );
  5004.     
  5005.     return ;
  5006. }
  5007.  
  5008.  
  5009. /*------------------------------------------------------------ */
  5010.  
  5011. /*
  5012.  * PictWindow_HandleEvent
  5013.  */
  5014. Boolean            PictWindow_HandleEvent( WindowPtr theWindow, const EventRecord *theEventRecord) 
  5015. {
  5016.     return false ;
  5017. }
  5018.  
  5019.  
  5020. /*------------------------------------------------------------ */
  5021.  
  5022. /*
  5023.  * PictWindow_New
  5024.  */
  5025. WindowPtr         PictWindow_New( unsigned char *windowTitle ) 
  5026. {
  5027.     return NULL ;
  5028. }
  5029.  
  5030.  
  5031. /*------------------------------------------------------------ */
  5032.  
  5033. /*
  5034.  * PictWindow_SaveAs
  5035.  */
  5036. OSErr             PictWindow_SaveAs( WindowPtr theWindow ) 
  5037. {
  5038.     short                dstPictFRef = 0 ;
  5039.     PicHandle            thePicture = NULL ;
  5040.     OSErr                theErr = noErr ;
  5041.     GWorldPtr            theGWorld ;
  5042.     CGrafPtr            savedPort ;
  5043.     GDHandle            savedGDH ;
  5044.     
  5045.     /* get an open a file for writing */
  5046.     if( (theErr = GetOutputPictFileRef( &dstPictFRef )) == noErr ) {
  5047.     
  5048.         theGWorld = GetGWorldFromPictWindow( theWindow ) ;
  5049.         
  5050.         /* make a temp viewer to use to make the PICT */
  5051.         if( theGWorld != NULL )
  5052.         {
  5053.             
  5054.             /* lock the viewer's GWorld for updates */
  5055.             LockPixels(GetGWorldPixMap(theGWorld)) ;
  5056.  
  5057.             GetGWorld( &savedPort, &savedGDH ) ;
  5058.             SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  5059.         
  5060.             thePicture = OpenPicture(&theGWorld->portRect) ;
  5061.             
  5062.             /* copy onto ourselves to make the picture */
  5063.             CopyBits ((BitMapPtr) &theGWorld->portPixMap,
  5064.                       (BitMapPtr) &theGWorld->portPixMap,
  5065.                       &theGWorld->portRect, 
  5066.                       &theGWorld->portRect, 
  5067.                       srcCopy, 
  5068.                       0L);
  5069.  
  5070.             ClosePicture() ;
  5071.         
  5072.             if( thePicture  != nil ) {
  5073.  
  5074.                  long                    length ;
  5075.                 long                    dummy ;
  5076.                 long                    index ;
  5077.  
  5078.                  /* ok, myPic now contains a handle to the picture */
  5079.                 HLock( (Handle)thePicture);
  5080.  
  5081.                 /* set up the 512 byte header for a PICT file */
  5082.                 dummy = 0;
  5083.                 
  5084.                 for( index = 0; index < ( 512 / 4 ); index ++ ){
  5085.                     length = 4 ;
  5086.                        
  5087.                        if( (theErr = FSWrite(dstPictFRef, &length, &dummy)) != noErr ) {
  5088.                         return theErr ;        
  5089.                     }
  5090.                 }                
  5091.                 
  5092.                    length = GetHandleSize( (Handle)thePicture);
  5093.                   
  5094.                    if( (theErr = FSWrite(dstPictFRef, &length, *thePicture)) != noErr ) {
  5095.                     return theErr ;        
  5096.                 }
  5097.              
  5098.                    /* now get rid of the picture handle */
  5099.                 HUnlock( (Handle) thePicture ) ;
  5100.                    KillPicture(thePicture);         
  5101.                 FSClose(dstPictFRef);
  5102.             }
  5103.         }
  5104.     }
  5105.     
  5106.     return theErr ;
  5107. }
  5108.  
  5109.  
  5110. /*------------------------------------------------------------ */
  5111.  
  5112. /*
  5113.  * PictWindow_Save
  5114.  */
  5115. OSErr             PictWindow_Save( WindowPtr theWindow ) 
  5116. {
  5117.     /* we don't really work well with pictures so just call save as */
  5118.     PictWindow_SaveAs( theWindow ) ;
  5119. }
  5120.  
  5121.  
  5122. /*------------------------------------------------------------ */
  5123.  
  5124. /*
  5125.  * PictWindow_Revert
  5126.  */
  5127. OSErr             PictWindow_Revert( WindowPtr theWindow ) 
  5128. {
  5129.     return noErr ;
  5130. }
  5131.  
  5132.  
  5133. /*------------------------------------------------------------ */
  5134.  
  5135. /*
  5136.  * PictWindow_Open
  5137.  */
  5138. WindowPtr         PictWindow_Open( FSSpec *theFSSpec ) 
  5139. {
  5140.     return NULL ;
  5141. }
  5142.  
  5143. /*------------------------------------------------------------ */
  5144.  
  5145. /*
  5146.  * PictWindow_Close
  5147.  */
  5148. OSErr PictWindow_Close( WindowPtr theWindow ) 
  5149. {
  5150.     DocumentHdl            theDocumentHdl ;
  5151.     PictDataHdl            thePictDataHdl ;
  5152.     GWorldPtr            theGWorld ;
  5153.     OSErr                theErr ;
  5154.     THPrint                thePrintRec ;
  5155.     
  5156.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5157.     if(theDocumentHdl != NULL
  5158.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  5159.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  5160.     {
  5161.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  5162.         {
  5163.             DisposeGWorld( theGWorld ) ;
  5164.         }
  5165.         DisposeHandle((Handle)thePictDataHdl) ;
  5166.  
  5167.         thePrintRec = (**theDocumentHdl).fPrintRec ;
  5168.         if( thePrintRec != NULL )
  5169.             DisposeHandle((Handle)thePrintRec ) ;
  5170.  
  5171.         DisposeHandle((Handle)theDocumentHdl) ;
  5172.         
  5173.     }
  5174.     DisposeWindow( theWindow ) ;
  5175.     return noErr ;
  5176. }
  5177.  
  5178.  
  5179. /*------------------------------------------------------------ */
  5180.  
  5181. /*
  5182.  * PictWindow_CountPages - calculate the number of pages needed to
  5183.  * image the document associated with the picture window
  5184.  */
  5185.  
  5186. short    PictWindow_CountPages( 
  5187.     WindowPtr    theWindow, 
  5188.     Rect         *pageRect ) 
  5189. {
  5190.     Rect            pictRect ;
  5191.     short            horizOffset, 
  5192.                     vertOffset,
  5193.                     pagesWide = 0,     /*  the number of pages wide the image is */
  5194.                     pagesHigh = 0,     /*  the number pages high for this image */
  5195.                     pageWidth,         /*  the width of one page */
  5196.                     pageHeight ;    /*  the height of one page */
  5197.  
  5198.     DocumentHdl        theDocumentHdl ;
  5199.     PictDataHdl        thePictDataHdl ;
  5200.     GWorldPtr        theGWorld ;
  5201.     OSErr            theErr ;
  5202.     short            retVal = 0 ;
  5203.     
  5204.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5205.     if(theDocumentHdl != NULL
  5206.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  5207.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  5208.     {
  5209.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  5210.         {
  5211.             retVal = GeneralCountPages( theGWorld, pageRect ) ;        
  5212.         }
  5213.     }
  5214.     
  5215.     return retVal ;
  5216. }
  5217.  
  5218. /*------------------------------------------------------------ */
  5219.  
  5220. /*
  5221.  * PictWindow_PrintPage - image the requested page in the 
  5222.  * printer port
  5223.  */
  5224.  
  5225. void    PictWindow_PrintPage( 
  5226.     WindowPtr         theWindow, 
  5227.     Rect             *pageRect, 
  5228.     GrafPtr         imagingPort, 
  5229.     short             pageNum ) 
  5230. {
  5231.     GWorldPtr        docGWorld;
  5232.     Rect            pictRect, rectToPrint,srcRect,dstRect;
  5233.     short            pagesWide,         /*  the number of pages wide the image is */
  5234.                     pagesHigh,         /*  the number pages high for this image */
  5235.                     horozTile,         /*  used in the loop to denote the H tile to print from the image */
  5236.                     vertTile ;         /*  used in the loop to denote the V tile to print from the image */
  5237.     short            thisPage = 1;    /*  used to find the page they want us to print */
  5238.     short            pictHOff,
  5239.                     pictVOff,
  5240.                     pictWidth,         /*  the width of the doc's GWorld */
  5241.                     pictHeight ;    /*  the height of the doc's GWorld */
  5242.     short            pageWidth,         /*  the width of one page */
  5243.                     pageHeight ;    /*  the height of one page */
  5244.     DocumentHdl        theDocumentHdl ;
  5245.     PictDataHdl        thePictDataHdl ;
  5246.     GWorldPtr        theGWorld ;
  5247.     OSErr            theErr ;
  5248.     PixMapHandle    offPixMap ;
  5249.     
  5250.     theDocumentHdl = (DocumentHdl)GetWRefCon(theWindow) ;
  5251.     if(theDocumentHdl != NULL
  5252.         && (**theDocumentHdl).fDocumentMagic == kPICTMagic
  5253.         && (thePictDataHdl = (PictDataHdl)((**theDocumentHdl).fPrivate)) != NULL) 
  5254.     {
  5255.         if((theGWorld = (**thePictDataHdl).fGWorld) != NULL) 
  5256.         {
  5257.             GeneralPrintPage( theGWorld, pageRect, imagingPort, pageNum ) ;
  5258.         }
  5259.     }
  5260. }
  5261.  
  5262.  
  5263. /*------------------------------------------------------------ */
  5264.  
  5265. /*
  5266.  * PictWindow_PostPrint - this gets called before we print, so any
  5267.  * setup for printing can be done here.
  5268.  */
  5269. void PictWindow_PrePrint( WindowPtr theWindow )
  5270. {
  5271.     return ; /* noop for picts, couild put null in the struct to avoid the call */
  5272. }
  5273.  
  5274.  
  5275. /*------------------------------------------------------------ */
  5276.  
  5277. /*
  5278.  * PictWindow_PostPrint - this gets called after we print, so any
  5279.  * setup for printing can be torn down here.
  5280.  */
  5281. void PictWindow_PostPrint( WindowPtr theWindow )
  5282. {
  5283.     return ; /* noop for picts, couild put null in the struct to avoid the call */
  5284. }
  5285.  
  5286.  
  5287. /*
  5288.  * handle the edit copy command.
  5289.  */
  5290. OSErr PictWindow_Copy( WindowPtr theWindow )
  5291. {
  5292.     PicHandle        thePicture ;
  5293.     OpenCPicParams    thePicParams ;
  5294.     GWorldPtr        theGWorld ;
  5295.     OSErr            theErr ;
  5296.     PixMapHandle    offPixMap ;
  5297.     
  5298.     if((theGWorld = GetGWorldFromPictWindow( theWindow )) != NULL) 
  5299.     {
  5300.         CGrafPtr        savedPort ;
  5301.         GDHandle        gdh ;
  5302.         
  5303.         /* save the port */
  5304.         GetGWorld( &savedPort, &gdh);
  5305.         SetGWorld( (CGrafPtr)theGWorld, NULL ) ;
  5306.                     
  5307.         /* set up the pic params for the OpenCPicture call */
  5308.         thePicParams.srcRect.top     = theGWorld->portRect.top;
  5309.         thePicParams.srcRect.left     = theGWorld->portRect.left;
  5310.         thePicParams.srcRect.bottom = theGWorld->portRect.bottom;
  5311.         thePicParams.srcRect.right     = theGWorld->portRect.right;
  5312.         thePicParams.hRes            = 0x00480000 ;                /* specifies 72 dpi */
  5313.         thePicParams.vRes            = 0x00480000 ;                /* specifies 72 dpi */
  5314.         thePicParams.version        = -2 ;
  5315.         thePicParams.reserved1        = 0 ;
  5316.         thePicParams.reserved2        = 0 ;
  5317.         
  5318.         /* try to create a new picture */
  5319.         thePicture = OpenCPicture( &thePicParams );
  5320.         
  5321.         if(thePicture != NULL)
  5322.         {
  5323.             long        aLong ;
  5324.             ClipRect( &thePicParams.srcRect );
  5325.  
  5326.             /* lock it down */
  5327.             offPixMap = GetGWorldPixMap( theGWorld ) ;
  5328.             LockPixels( offPixMap ) ;    
  5329.             
  5330.             /* make the picture */    
  5331.             CopyBits(    (BitMapPtr)*offPixMap, 
  5332.                         (BitMapPtr)*offPixMap, 
  5333.                         & theGWorld->portRect, 
  5334.                         & theGWorld->portRect, 
  5335.                         srcCopy, 
  5336.                         0L ) ;
  5337.                         
  5338.             ClosePicture() ;
  5339.  
  5340.             /* unlock */
  5341.             UnlockPixels( offPixMap ) ;
  5342.                         
  5343.             /* place the picture on the scrap */
  5344.             HLock((Handle)thePicture) ;
  5345.             aLong = ZeroScrap() ;
  5346.             aLong = PutScrap(GetHandleSize((Handle)thePicture), 'PICT', *thePicture);
  5347.             HUnlock((Handle)thePicture) ;
  5348.             KillPicture(thePicture) ;
  5349.                 
  5350.         }
  5351.         /* reset the port */    
  5352.         SetGWorld( savedPort, gdh);
  5353.             
  5354.     }
  5355.     return ; 
  5356. }
  5357.  
  5358.  
  5359.